@@ -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,154 @@ 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 , Callable constructor , Expr receiver ) {
663+ constructor = i .getTargetImpl ( _) and
664+ constructor .asCallable ( ) instanceof ConstructorDeclaration and
665+ receiver = i .getArgument ( 0 )
666+ }
667+
668+ /**
669+ * Since we handle constructors as instance methods without return types,
670+ * we need to explicitly handle constructors where (parts of) the type of
671+ * the constructed object must be inferred from the context.
672+ *
673+ * Example:
674+ *
675+ * ```swift
676+ * class C<T1, T2> {
677+ * init(x : T1) { ... } // `T2` must be inferred from the context
678+ * }
679+ * ```
680+ */
681+ private module ContextualConstructorReturnTypeInput implements
682+ M3:: ContextualTyping:: ContextualReturnTypeInputSig
683+ {
684+ predicate callableHasTypeParameterAtReturnType ( Callable c , TypePath path , TypeParameter tp ) {
685+ c .asCallable ( ) instanceof ConstructorDeclaration and
686+ tp = c .getDeclaringType ( ) .getTypeAt ( path )
687+ }
688+
689+ Parameter getACallableParameter ( Callable c ) {
690+ result = c .getParameter ( _) and
691+ not result .getParameterEx ( ) .isImplicitReceiverParameter ( _)
692+ }
693+ }
694+
695+ private module ContextualConstructorReturnType =
696+ M3:: ContextualTyping:: ContextualReturnType< ContextualConstructorReturnTypeInput > ;
697+
698+ private predicate needsContextualTyping ( Invocation i , TypePath path ) {
699+ exists ( Callable constructor , Expr receiver , ClassLikeDeclarationType receiverType |
700+ constructionReceiver ( i , constructor , receiver ) and
701+ receiverType = inferType ( receiver )
702+ |
703+ ContextualConstructorReturnType:: needsContextualTyping ( i , path ) and
704+ receiverType = constructor .getDeclaringType ( ) .getType ( )
705+ or
706+ // inherited constructor
707+ exists (
708+ ClassLikeDeclarationType declType , TypeAbstraction abs , TypeMention constraint ,
709+ TypeParameter tp
710+ |
711+ declType = constructor .getDeclaringType ( ) .getType ( ) and
712+ BaseTypes:: rootTypesSatisfaction ( receiverType , declType , abs , _, constraint ) and
713+ path = TypePath:: singleton ( tp )
714+ |
715+ // `A<T> : B<T>`
716+ exists ( TypePath path0 |
717+ BaseTypes:: conditionSatisfiesConstraintTypeAt ( abs , _, constraint , path0 , tp ) and
718+ ContextualConstructorReturnType:: needsContextualTyping ( i , path0 )
719+ )
720+ or
721+ // `A<T> : B`
722+ tp = receiverType .getATypeParameter ( ) and
723+ not BaseTypes:: conditionSatisfiesConstraintTypeAt ( abs , _, constraint , _, tp )
724+ )
725+ )
726+ }
727+
728+ /**
729+ * Propagate type information from the receiver of a construction to the construction
730+ * itself.
731+ *
732+ * Note that this works both for calls with synthetic receivers, `A.init(0)` or `A(0)`,
733+ * as well as calls receivers, `self.init(0)` or `super.init(0)`.
734+ */
735+ predicate step ( AstNode n1 , TypePath prefix1 , AstNode n2 , TypePath prefix2 ) {
736+ constructionReceiver ( n2 , _, n1 ) and
737+ prefix1 .isEmpty ( ) and
738+ prefix2 .isEmpty ( )
739+ }
740+
741+ Type inferType ( AstNode n , TypePath path ) {
742+ n =
743+ any ( TypeMention tm |
744+ tm = getSyntheticConstructionReceiver ( _) and
745+ result = tm .getTypeAt ( path )
746+ )
747+ or
748+ needsContextualTyping ( n , path ) and
749+ result instanceof UnknownType
750+ }
751+
752+ predicate allowFullContextualInference ( TypeMention tm , TypePath path ) {
753+ // For a construction such as `Optional.some(0)`, we need contextual inference
754+ // to infer the type of the wrapped object
755+ tm = getSyntheticConstructionReceiver ( _) and
756+ exists ( TypePath prefix , Type t , TypeParameter tp |
757+ t = tm .getTypeAt ( prefix ) and
758+ not t instanceof UnknownType and
759+ tp = t .getATypeParameter ( ) and
760+ path = TypePath:: snoc ( prefix , tp ) and
761+ not exists ( tm .getTypeAt ( path ) )
762+ )
763+ }
764+ }
765+
615766 Type inferTypeLanguageSpecific ( AstNode n , TypePath path ) {
616767 result = Plugin:: inferType ( n , path )
617768 or
@@ -650,10 +801,16 @@ module Input3 implements InputSig3 {
650801 n .( ArrayLiteral ) .getNumberOfElements ( ) = 0 and
651802 path = TypePath:: singleton ( getArrayElementTypeParameter ( ) ) and
652803 result instanceof UnknownType
804+ or
805+ result = Construction:: inferType ( n , path )
653806 }
654807
655808 pragma [ nomagic]
656809 Type inferTypeCertainLanguageSpecific ( AstNode n , TypePath path ) { none ( ) }
810+
811+ predicate allowFullContextualInference ( AstNode n , TypePath path ) {
812+ Construction:: allowFullContextualInference ( n , path )
813+ }
657814}
658815
659816private module M3 = Make3< Input3 > ;
0 commit comments