@@ -135,7 +135,11 @@ module Input3 implements InputSig3 {
135135 class AstNode = Unified:: AstNode ;
136136
137137 class Expr extends Unified:: Expr {
138- Expr ( ) { isInAssignmentContext ( this , _) or hasResultValue ( this ) }
138+ Expr ( ) {
139+ isInAssignmentContext ( this , _) or
140+ hasResultValue ( this ) or
141+ this = Construction:: getSyntheticConstructionReceiver ( _)
142+ }
139143 }
140144
141145 class Cast extends Expr , TypeCastExpr {
@@ -270,6 +274,7 @@ module Input3 implements InputSig3 {
270274
271275 pragma [ nomagic]
272276 private predicate lookupMember0 ( MemberAccessExpr mae , ClassLikeDeclaration cls , string name ) {
277+ not exists ( getStaticBindingTargetFromRef ( mae ) ) and // if a static member can be resolved, use it
273278 cls = inferType ( mae .getBase ( ) ) .( ClassLikeDeclarationType ) .getClassLikeDeclaration ( ) and
274279 name = mae .getMemberName ( )
275280 }
@@ -393,12 +398,7 @@ module Input3 implements InputSig3 {
393398 )
394399 }
395400
396- override TypeMention getType ( ) {
397- result = c .getReturnType ( )
398- or
399- c instanceof ConstructorDeclaration and
400- result = this .getDeclaringType ( )
401- }
401+ override TypeMention getType ( ) { result = c .getReturnType ( ) }
402402
403403 override Identifier getNameNode ( ) {
404404 result = c .( AccessorDeclaration ) .getNameNode ( )
@@ -456,26 +456,29 @@ module Input3 implements InputSig3 {
456456
457457 class InvocationResolutionContext = Unit ;
458458
459+ private TypeMention getQualifierTypeMention ( CallExpr ce ) {
460+ result = ce .getCallee ( )
461+ or
462+ not ce .getCallee ( ) instanceof TypeMention and
463+ result = ce .getCallee ( ) .( MemberAccessExpr ) .getBase ( )
464+ }
465+
459466 class Invocation extends Expr , CallExpr {
460- Type getTypeQualifier ( TypePath path ) {
461- exists ( TypeMention tm | result = tm .getTypeAt ( path ) |
462- tm = super .getCallee ( )
463- or
464- not super .getCallee ( ) instanceof TypeMention and
465- tm = super .getCallee ( ) .( MemberAccessExpr ) .getBase ( )
466- )
467- }
467+ Type getTypeQualifier ( TypePath path ) { result = getQualifierTypeMention ( this ) .getTypeAt ( path ) }
468468
469469 Type getTypeArgument ( int i , TypePath path ) { none ( ) }
470470
471- int getNumberOfArguments ( ) { result = CallExpr .super .getNumberOfArguments ( ) + 1 }
472-
473471 Expr getArgument ( int i ) {
474472 i = 0 and
475- exists ( boolean isFunctionExprInvoke | exists ( this .getTargetImpl ( isFunctionExprInvoke ) ) |
476- if isFunctionExprInvoke = true
477- then result = CallExpr .super .getCallee ( )
478- else result = CallExpr .super .getCallee ( ) .( MemberAccessExpr ) .getBase ( )
473+ (
474+ result = Construction:: getSyntheticConstructionReceiver ( this )
475+ or
476+ not exists ( Construction:: getSyntheticConstructionReceiver ( this ) ) and
477+ exists ( boolean isFunctionExprInvoke | exists ( this .getTargetImpl ( isFunctionExprInvoke ) ) |
478+ if isFunctionExprInvoke = true
479+ then result = CallExpr .super .getCallee ( )
480+ else result = CallExpr .super .getCallee ( ) .( MemberAccessExpr ) .getBase ( )
481+ )
479482 )
480483 or
481484 result = CallExpr .super .getArgument ( i - 1 ) .getValue ( )
@@ -488,13 +491,13 @@ module Input3 implements InputSig3 {
488491 result = getFunctionInvoke ( t )
489492 }
490493
491- private Callable getTargetViaStaticNameBinding ( ) {
494+ Callable getTargetViaStaticNameBinding ( ) {
492495 exists ( NameBinding b | b = getStaticBindingTargetFromRef ( this .getCallee ( ) ) |
493496 // object creation (including enum constructors): `String(42)`, `Optional.Some(42)`
494- exists ( ClassLikeDeclaration cls , ConstructorDeclaration init |
497+ exists ( ClassLikeDeclaration cls |
495498 cls .getNameNode ( ) = b and
496- init = cls . getAMember ( ) and
497- result .asCallable ( ) = init
499+ result . isInstanceMemberOf ( cls , _ ) and
500+ result .asCallable ( ) instanceof ConstructorDeclaration
498501 )
499502 or
500503 // call without explicit receiver: `foo(42)`
@@ -535,13 +538,13 @@ module Input3 implements InputSig3 {
535538 result = inferType ( invocation .( CallExpr ) .getCallee ( ) , path )
536539 or
537540 exists ( TypePath prefix , TypePath suffix , int j |
538- functionInvokeSignature ( t , invocation .getNumberOfArguments ( ) - 1 , j , i , prefix ) and
541+ functionInvokeSignature ( t , invocation .getNumberOfArguments ( ) , j , i , prefix ) and
539542 result = inferType ( invocation .getArgument ( j + 1 ) , suffix ) and
540543 path = prefix .append ( suffix )
541544 )
542545 )
543546 or
544- // A call to a regular function or method
547+ // A non- function-expression call
545548 exists ( invocation .getTargetImpl ( false ) ) and
546549 (
547550 result = inferType ( invocation .getArgument ( i ) , path )
@@ -612,6 +615,144 @@ module Input3 implements InputSig3 {
612615 )
613616 }
614617
618+ predicate stepLanguageSpecificExtra ( AstNode n1 , TypePath prefix1 , AstNode n2 , TypePath prefix2 ) {
619+ Construction:: step ( n1 , prefix1 , n2 , prefix2 )
620+ }
621+
622+ /**
623+ * Provides logic for resolving types of constructor invocations.
624+ *
625+ * Constructors are treated as instance methods without return types, in order
626+ * to be able to handle inherited constructors similar to ordinary instance
627+ * methods:
628+ *
629+ * ```swift
630+ * class A<Ta> {
631+ * init(x : Ta) { ... }
632+ * }
633+ *
634+ * class B<Tb> : A<Tb?> { }
635+ *
636+ * A.init(0); // (1) has type `A<Int>`
637+ * B.init(.some(0)); // (2) has type `B<Int>`
638+ * B<Int>(.none); // (3) has type `B<Int>`
639+ * ```
640+ *
641+ * Because the constructor calls are treated as normal instance method calls,
642+ * we use the type qualifier to represent the receiver, and then allow for
643+ * contextual type information to flow into the receiver:
644+ *
645+ * (1) The receiver has type `A`, `Ta` is inferred to be instantiated to `Int`,
646+ * which is propagated directly back into the receiver.
647+ * (2) The receiver has type `B`, `Ta` is inferred to be instantiated to `Int?`
648+ * which in turn means `Tb` is inferred to be instantiated to `Int`, which
649+ * is then propagated back into the receiver.
650+ * (3) The receiver has type `B<Int>`, and no further type inference is needed.
651+ */
652+ private module Construction {
653+ /**
654+ * Gets the AST node that is used to represent the receiver in a constructor
655+ * invocation without an actual receiver.
656+ */
657+ TypeMention getSyntheticConstructionReceiver ( Invocation invocation ) {
658+ invocation .getTargetViaStaticNameBinding ( ) .asCallable ( ) instanceof ConstructorDeclaration and
659+ result = getQualifierTypeMention ( invocation )
660+ }
661+
662+ private predicate constructionReceiver ( Invocation i , ConstructorDeclaration cd , Expr receiver ) {
663+ cd = i .getTargetImpl ( _) .asCallable ( ) and
664+ receiver = i .getArgument ( 0 )
665+ }
666+
667+ /**
668+ * Since we handle constructors as instance methods without return types,
669+ * we need to explicitly handle constructors where (parts of) the type of
670+ * the constructed object must be inferred from the context.
671+ *
672+ * Example:
673+ *
674+ * ```swift
675+ * class C<T1, T2> {
676+ * init(x : T1) { ... } // `T2` must be inferred from the context
677+ * }
678+ * ```
679+ */
680+ private module ContextualConstructorReturnTypeInput implements
681+ M3:: ContextualTyping:: ContextualReturnTypeInputSig
682+ {
683+ predicate callableHasTypeParameterAtReturnType ( Callable c , TypePath path , TypeParameter tp ) {
684+ c .asCallable ( ) instanceof ConstructorDeclaration and
685+ tp = c .getDeclaringType ( ) .getTypeAt ( path )
686+ }
687+
688+ Parameter getACallableParameter ( Callable c ) {
689+ result = c .getParameter ( _) and
690+ not result .getParameterEx ( ) .isImplicitReceiverParameter ( _)
691+ }
692+ }
693+
694+ private module ContextualConstructorReturnType =
695+ M3:: ContextualTyping:: ContextualReturnType< ContextualConstructorReturnTypeInput > ;
696+
697+ private predicate needsContextualTyping ( Invocation i , TypePath path ) {
698+ exists (
699+ ConstructorDeclaration cd , Expr receiver , ClassLikeDeclaration declType , TypePath path0
700+ |
701+ constructionReceiver ( i , cd , receiver ) and
702+ declType = inferType ( receiver ) .( ClassLikeDeclarationType ) .getClassLikeDeclaration ( ) and
703+ ContextualConstructorReturnType:: needsContextualTyping ( i , path0 )
704+ |
705+ declType .getAMember ( ) = cd and
706+ path = path0
707+ or
708+ // inherited constructor
709+ exists ( TypeAbstraction abs , TypeMention constraint , TypeParameter tp |
710+ BaseTypes:: rootTypesSatisfaction ( TClassLikeDeclarationType ( declType ) , _, abs , _,
711+ constraint ) and
712+ BaseTypes:: conditionSatisfiesConstraintTypeAt ( abs , _, constraint , path0 , tp ) and
713+ path = TypePath:: singleton ( tp )
714+ )
715+ )
716+ }
717+
718+ /**
719+ * Propagate type information from the receiver of a construction to the construction
720+ * itself.
721+ *
722+ * Note that this works both for calls with synthetic receivers, `A.init(0)` or `A(0)`,
723+ * as well as calls receivers, `self.init(0)` or `super.init(0)`.
724+ */
725+ predicate step ( AstNode n1 , TypePath prefix1 , AstNode n2 , TypePath prefix2 ) {
726+ constructionReceiver ( n2 , _, n1 ) and
727+ prefix1 .isEmpty ( ) and
728+ prefix2 .isEmpty ( )
729+ }
730+
731+ Type inferType ( AstNode n , TypePath path ) {
732+ n =
733+ any ( TypeMention tm |
734+ tm = getSyntheticConstructionReceiver ( _) and
735+ result = tm .getTypeAt ( path )
736+ )
737+ or
738+ needsContextualTyping ( n , path ) and
739+ result instanceof UnknownType
740+ }
741+
742+ predicate allowFullContextualInference ( TypeMention tm , TypePath path ) {
743+ // For a construction such as `Optional.some(0)`, we need contextual inference
744+ // to infer the type of the wrapped object
745+ tm = getSyntheticConstructionReceiver ( _) and
746+ exists ( TypePath prefix , Type t , TypeParameter tp |
747+ t = tm .getTypeAt ( prefix ) and
748+ not t instanceof UnknownType and
749+ tp = t .getATypeParameter ( ) and
750+ path = TypePath:: snoc ( prefix , tp ) and
751+ not exists ( tm .getTypeAt ( path ) )
752+ )
753+ }
754+ }
755+
615756 Type inferTypeLanguageSpecific ( AstNode n , TypePath path ) {
616757 result = Plugin:: inferType ( n , path )
617758 or
@@ -650,10 +791,16 @@ module Input3 implements InputSig3 {
650791 n .( ArrayLiteral ) .getNumberOfElements ( ) = 0 and
651792 path = TypePath:: singleton ( getArrayElementTypeParameter ( ) ) and
652793 result instanceof UnknownType
794+ or
795+ result = Construction:: inferType ( n , path )
653796 }
654797
655798 pragma [ nomagic]
656799 Type inferTypeCertainLanguageSpecific ( AstNode n , TypePath path ) { none ( ) }
800+
801+ predicate allowFullContextualInference ( AstNode n , TypePath path ) {
802+ Construction:: allowFullContextualInference ( n , path )
803+ }
657804}
658805
659806private module M3 = Make3< Input3 > ;
0 commit comments