26
26
#include " swift/AST/ASTWalker.h"
27
27
#include " swift/AST/ExistentialLayout.h"
28
28
#include " swift/AST/Initializer.h"
29
+ #include " swift/AST/GenericEnvironment.h"
29
30
#include " swift/AST/GenericSignature.h"
30
31
#include " swift/AST/ParameterList.h"
31
32
#include " swift/AST/ProtocolConformance.h"
@@ -378,6 +379,66 @@ namespace {
378
379
return base.getOldType ();
379
380
}
380
381
382
+ // Returns None if the AST does not contain enough information to recover
383
+ // substitutions; this is different from an Optional(SubstitutionMap()),
384
+ // indicating a valid call to a non-generic operator.
385
+ Optional<SubstitutionMap>
386
+ getOperatorSubstitutions (ValueDecl *witness, Type refType) {
387
+ // We have to recover substitutions in this hacky way because
388
+ // the AST does not retain enough information to devirtualize
389
+ // calls like this.
390
+ auto witnessType = witness->getInterfaceType ();
391
+
392
+ // Compute the substitutions.
393
+ auto *gft = witnessType->getAs <GenericFunctionType>();
394
+ if (gft == nullptr ) {
395
+ if (refType->isEqual (witnessType))
396
+ return SubstitutionMap ();
397
+ return None;
398
+ }
399
+
400
+ auto sig = gft->getGenericSignature ();
401
+ auto *env = sig->getGenericEnvironment ();
402
+
403
+ witnessType = FunctionType::get (gft->getParams (),
404
+ gft->getResult (),
405
+ gft->getExtInfo ());
406
+ witnessType = env->mapTypeIntoContext (witnessType);
407
+
408
+ TypeSubstitutionMap subs;
409
+ auto substType = witnessType->substituteBindingsTo (
410
+ refType,
411
+ [&](ArchetypeType *origType, CanType substType) -> CanType {
412
+ if (auto gpType = dyn_cast<GenericTypeParamType>(
413
+ origType->getInterfaceType ()->getCanonicalType ()))
414
+ subs[gpType] = substType;
415
+
416
+ return substType;
417
+ });
418
+
419
+ // If substitution failed, it means that the protocol requirement type
420
+ // and the witness type did not match up. The only time that this
421
+ // should happen is when the witness is defined in a base class and
422
+ // the actual call uses a derived class. For example,
423
+ //
424
+ // protocol P { func +(lhs: Self, rhs: Self) }
425
+ // class Base : P { func +(lhs: Base, rhs: Base) {} }
426
+ // class Derived : Base {}
427
+ //
428
+ // If we enter this code path with two operands of type Derived,
429
+ // we know we're calling the protocol requirement P.+, with a
430
+ // substituted type of (Derived, Derived) -> (). But the type of
431
+ // the witness is (Base, Base) -> (). Just bail out and make a
432
+ // witness method call in this rare case; SIL mandatory optimizations
433
+ // will likely devirtualize it anyway.
434
+ if (!substType)
435
+ return None;
436
+
437
+ return SubstitutionMap::get (sig,
438
+ QueryTypeSubstitutionMap{subs},
439
+ TypeChecker::LookUpConformance (cs.DC ));
440
+ }
441
+
381
442
public:
382
443
// / Build a reference to the given declaration.
383
444
Expr *buildDeclRef (SelectedOverload overload, DeclNameLoc loc,
@@ -400,56 +461,53 @@ namespace {
400
461
401
462
// Handle operator requirements found in protocols.
402
463
if (auto proto = dyn_cast<ProtocolDecl>(decl->getDeclContext ())) {
403
- // If we don't have an archetype or existential, we have to call the
404
- // witness.
464
+ // If we have a concrete conformance, build a call to the witness.
465
+ //
405
466
// FIXME: This is awful. We should be able to handle this as a call to
406
467
// the protocol requirement with Self == the concrete type, and SILGen
407
468
// (or later) can devirtualize as appropriate.
408
- if (!baseTy->is <ArchetypeType>() && !baseTy->isAnyExistentialType ()) {
409
- auto conformance =
410
- TypeChecker::conformsToProtocol (
411
- baseTy, proto, cs.DC ,
412
- ConformanceCheckFlags::InExpression);
413
- if (conformance.isConcrete ()) {
414
- if (auto witness =
415
- conformance.getConcrete ()->getWitnessDecl (decl)) {
416
- // Hack up an AST that we can type-check (independently) to get
417
- // it into the right form.
418
- // FIXME: the hop through 'getDecl()' is because
419
- // SpecializedProtocolConformance doesn't substitute into
420
- // witnesses' ConcreteDeclRefs.
421
- Type expectedFnType = simplifyType (overload.openedType );
422
- assert (expectedFnType->isEqual (
423
- fullType->castTo <AnyFunctionType>()->getResult ()) &&
424
- " Cannot handle adjustments made to the opened type" );
469
+ auto conformance =
470
+ TypeChecker::conformsToProtocol (
471
+ baseTy, proto, cs.DC ,
472
+ ConformanceCheckFlags::InExpression);
473
+ if (conformance.isConcrete ()) {
474
+ if (auto witness = conformance.getConcrete ()->getWitnessDecl (decl)) {
475
+ // The fullType was computed by substituting the protocol
476
+ // requirement so it always has a (Self) -> ... curried
477
+ // application. Strip it off if the witness was a top-level
478
+ // function.
479
+ Type refType;
480
+ if (witness->getDeclContext ()->isTypeContext ())
481
+ refType = fullType;
482
+ else
483
+ refType = fullType->castTo <AnyFunctionType>()->getResult ();
484
+
485
+ // Build the AST for the call to the witness.
486
+ auto subMap = getOperatorSubstitutions (witness, refType);
487
+ if (subMap) {
488
+ ConcreteDeclRef witnessRef (witness, *subMap);
489
+ auto declRefExpr = new (ctx) DeclRefExpr (witnessRef, loc,
490
+ /* Implicit=*/ false );
491
+ declRefExpr->setFunctionRefKind (choice.getFunctionRefKind ());
492
+ cs.setType (declRefExpr, refType);
493
+
425
494
Expr *refExpr;
426
495
if (witness->getDeclContext ()->isTypeContext ()) {
496
+ // If the operator is a type member, add the implicit
497
+ // (Self) -> ... call.
427
498
Expr *base =
428
499
TypeExpr::createImplicitHack (loc.getBaseNameLoc (), baseTy,
429
500
ctx);
430
- refExpr = new (ctx) MemberRefExpr (base, SourceLoc (), witness,
431
- loc, /* Implicit=*/ true );
501
+ cs.setType (base, MetatypeType::get (baseTy));
502
+
503
+ refExpr = new (ctx) DotSyntaxCallExpr (declRefExpr,
504
+ SourceLoc (), base);
505
+ auto refType = fullType->castTo <FunctionType>()->getResult ();
506
+ cs.setType (refExpr, refType);
432
507
} else {
433
- auto declRefExpr = new (ctx) DeclRefExpr (witness, loc,
434
- /* Implicit=*/ false );
435
- declRefExpr->setFunctionRefKind (choice.getFunctionRefKind ());
436
508
refExpr = declRefExpr;
437
509
}
438
510
439
- auto resultTy = TypeChecker::typeCheckExpression (
440
- refExpr, cs.DC , TypeLoc::withoutLoc (expectedFnType),
441
- CTP_CannotFail);
442
- if (!resultTy)
443
- return nullptr ;
444
-
445
- cs.cacheExprTypes (refExpr);
446
-
447
- // Remove an outer function-conversion expression. This
448
- // happens when we end up referring to a witness for a
449
- // superclass conformance, and 'Self' differs.
450
- if (auto fnConv = dyn_cast<FunctionConversionExpr>(refExpr))
451
- refExpr = fnConv->getSubExpr ();
452
-
453
511
return forceUnwrapIfExpected (refExpr, choice, locator);
454
512
}
455
513
}
0 commit comments