@@ -138,8 +138,7 @@ module Input3 implements InputSig3 {
138138 Expr ( ) {
139139 isInAssignmentContext ( this , _) or
140140 hasResultValue ( this ) or
141- this = any ( CallExpr ce ) .getCallee ( ) or
142- this = any ( Expr e ) .( MemberAccessExpr ) .getBase ( )
141+ this = Construction:: getConstructionReceiver ( _)
143142 }
144143 }
145144
@@ -455,31 +454,31 @@ module Input3 implements InputSig3 {
455454
456455 Callable getEnclosingCallable ( AstNode node ) { result .asCallable ( ) = node .getEnclosingCallable ( ) }
457456
458- private newtype CallKind =
459- Invoke ( ) or
460- Constructor ( ) or
461- Ordinary ( )
462-
463457 class InvocationResolutionContext = Unit ;
464458
465- class Invocation extends Expr , CallExpr {
466- TypeMention getReceiverTypeMention ( ) {
467- result = super .getCallee ( )
468- or
469- not super .getCallee ( ) instanceof TypeMention and
470- result = super .getCallee ( ) .( MemberAccessExpr ) .getBase ( )
471- }
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+ }
472465
473- Type getTypeQualifier ( TypePath path ) { result = this .getReceiverTypeMention ( ) .getTypeAt ( path ) }
466+ class Invocation extends Expr , CallExpr {
467+ Type getTypeQualifier ( TypePath path ) { result = getQualifierTypeMention ( this ) .getTypeAt ( path ) }
474468
475469 Type getTypeArgument ( int i , TypePath path ) { none ( ) }
476470
477471 Expr getArgument ( int i ) {
478472 i = 0 and
479- exists ( CallKind kind | exists ( this .getTargetImpl ( kind ) ) |
480- if kind = [ Invoke ( ) .( CallKind ) , Constructor ( ) ]
481- then result = CallExpr .super .getCallee ( )
482- else result = CallExpr .super .getCallee ( ) .( MemberAccessExpr ) .getBase ( )
473+ (
474+ result = Construction:: getConstructionReceiver ( this )
475+ or
476+ not exists ( Construction:: getConstructionReceiver ( 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+ )
483482 )
484483 or
485484 result = CallExpr .super .getArgument ( i - 1 ) .getValue ( )
@@ -492,41 +491,40 @@ module Input3 implements InputSig3 {
492491 result = getFunctionInvoke ( t )
493492 }
494493
495- Callable getTargetViaStaticNameBinding ( CallKind kind ) {
494+ Callable getTargetViaStaticNameBinding ( ) {
496495 exists ( NameBinding b | b = getStaticBindingTargetFromRef ( this .getCallee ( ) ) |
497496 // object creation (including enum constructors): `String(42)`, `Optional.Some(42)`
498497 exists ( ClassLikeDeclaration cls |
499498 cls .getNameNode ( ) = b and
500499 result .isInstanceMemberOf ( cls , _) and
501- result .asCallable ( ) instanceof ConstructorDeclaration and
502- kind = Constructor ( )
500+ result .asCallable ( ) instanceof ConstructorDeclaration
503501 )
504502 or
505503 // call without explicit receiver: `foo(42)`
506- result .getNameNode ( ) = b and
507- kind = Ordinary ( )
504+ result .getNameNode ( ) = b
508505 )
509506 }
510507
511- Callable getTargetImpl ( CallKind kind ) {
508+ Callable getTargetImpl ( boolean isFunctionExprInvoke ) {
512509 // mutual recursion; call with explicit receiver: `obj.foo(42)`
513510 result = lookupInstanceMember ( this .getCallee ( ) ) and
514- kind = Ordinary ( )
511+ isFunctionExprInvoke = false
515512 or
516513 // mutual recursion; call to a function expression: `callback(42)`
517514 result .asCallable ( ) = this .getInvokeTarget ( _) and
518- kind = Invoke ( )
515+ isFunctionExprInvoke = true
519516 or
520517 // no mutual recursion; can be resolved directly with static name binding
521- result = this .getTargetViaStaticNameBinding ( kind )
518+ result = this .getTargetViaStaticNameBinding ( ) and
519+ isFunctionExprInvoke = false
522520 }
523521
524522 Callable getTarget ( InvocationResolutionContext c ) {
525523 result = this .getTargetImpl ( _) and
526524 exists ( c )
527525 }
528526
529- Callable getATargetForTypeQualifierMatching ( ) { result = this .getTargetViaStaticNameBinding ( _ ) }
527+ Callable getATargetForTypeQualifierMatching ( ) { result = this .getTargetViaStaticNameBinding ( ) }
530528 }
531529
532530 Type inferInvocationArgumentType (
@@ -547,10 +545,8 @@ module Input3 implements InputSig3 {
547545 )
548546 or
549547 // A non-function-expression call
550- exists ( CallKind kind |
551- exists ( invocation .getTargetImpl ( kind ) ) and
552- kind != Invoke ( )
553- |
548+ exists ( invocation .getTargetImpl ( false ) ) and
549+ (
554550 result = inferType ( invocation .getArgument ( i ) , path )
555551 or
556552 i = 0 and
@@ -620,7 +616,7 @@ module Input3 implements InputSig3 {
620616 }
621617
622618 /**
623- * Provides logic for resolving the types of constructor invocations.
619+ * Provides logic for resolving types of constructor invocations.
624620 *
625621 * Constructors are treated as instance methods without return types, in order
626622 * to be able to handle inherited constructors similar to ordinary instance
@@ -650,11 +646,26 @@ module Input3 implements InputSig3 {
650646 * (3) The receiver has type `B<Int>`, and no further type inference is needed.
651647 */
652648 private module Construction {
653- private TypeMention getAReceiverTypeMention ( ) {
654- exists ( Invocation invocation |
655- invocation .getTargetViaStaticNameBinding ( _) .asCallable ( ) instanceof ConstructorDeclaration and
656- result = invocation .getReceiverTypeMention ( )
657- )
649+ /**
650+ * Gets the AST node that is used to represent the receiver in a constructor
651+ * invocation.
652+ */
653+ TypeMention getConstructionReceiver ( Invocation invocation ) {
654+ invocation .getTargetViaStaticNameBinding ( ) .asCallable ( ) instanceof ConstructorDeclaration and
655+ result = getQualifierTypeMention ( invocation )
656+ }
657+
658+ /**
659+ * Gets the inferred type at `path` of the object constructed at `i` using constructor
660+ * `cd`. Because of how we handle constructors as instance methods without return types,
661+ * this is simply the inferred type of the receiver.
662+ *
663+ * Note that this works for both calls without an actual receiver, `A.init(0)` or `A(0)`,
664+ * as well as calls with a receiver, `self.init(0)` or `super.init(0)`.
665+ */
666+ private Type inferConstructionType ( Invocation i , ConstructorDeclaration cd , TypePath path ) {
667+ cd = i .getTargetImpl ( _) .asCallable ( ) and
668+ result = inferType ( i .getArgument ( 0 ) , path )
658669 }
659670
660671 /**
@@ -687,16 +698,6 @@ module Input3 implements InputSig3 {
687698 private module ContextualConstructorReturnType =
688699 M3:: ContextualTyping:: ContextualReturnType< ContextualConstructorReturnTypeInput > ;
689700
690- /**
691- * Gets the inferred type at `path` of the object constructed at `i` using constructor
692- * `cd`. Because of how we handle constructors as instance methods without return types,
693- * this is simply the inferred type of the receiver.
694- */
695- private Type inferConstructionType ( Invocation i , ConstructorDeclaration cd , TypePath path ) {
696- cd = i .getTargetImpl ( _) .asCallable ( ) and
697- result = inferType ( i .getArgument ( 0 ) , path )
698- }
699-
700701 private predicate needsContextualTyping ( Invocation i , TypePath path ) {
701702 exists ( ConstructorDeclaration cd , ClassLikeDeclaration declType , TypePath path0 |
702703 declType =
@@ -719,11 +720,11 @@ module Input3 implements InputSig3 {
719720 }
720721
721722 Type inferConstructionType ( AstNode n , TypePath path ) {
722- exists ( TypeMention tm |
723- n = tm and
724- tm = getAReceiverTypeMention ( ) and
725- result = tm .getTypeAt ( path )
726- )
723+ n =
724+ any ( TypeMention tm |
725+ tm = getConstructionReceiver ( _ ) and
726+ result = tm .getTypeAt ( path )
727+ )
727728 or
728729 result = inferConstructionType ( n , _, path )
729730 or
@@ -734,7 +735,7 @@ module Input3 implements InputSig3 {
734735 predicate allowFullContextualInference ( TypeMention tm , TypePath path ) {
735736 // For a construction such as `Optional.some(0)`, we need contextual inference
736737 // to infer the type of the wrapped object
737- tm = getAReceiverTypeMention ( ) and
738+ tm = getConstructionReceiver ( _ ) and
738739 exists ( TypePath prefix , Type t , TypeParameter tp |
739740 t = tm .getTypeAt ( prefix ) and
740741 not t instanceof UnknownType and
0 commit comments