Skip to content

Commit ac35173

Browse files
committed
construction
1 parent bdd5a7c commit ac35173

2 files changed

Lines changed: 249 additions & 191 deletions

File tree

rust/ql/lib/codeql/rust/internal/typeinference/TypeInference.qll

Lines changed: 140 additions & 177 deletions
Original file line numberDiff line numberDiff line change
@@ -582,6 +582,137 @@ private module Input3 implements InputSig3 {
582582
}
583583
}
584584

585+
final class Constructor = ConstructorImpl;
586+
587+
abstract private class ConstructorImpl extends Addressable {
588+
TypeMention getAdditionalTypeParameterConstraint(TypeParameter tp) { none() }
589+
590+
final TypeParameter getTypeParameter(TypeParameterPosition ppos) {
591+
result = ppos.asTypeParameter() and
592+
ppos.asTypeParam() = this.getTypeItem().getGenericParamList().getATypeParam()
593+
}
594+
595+
abstract TypeItem getTypeItem();
596+
597+
abstract TypeRepr getParameterTypeRepr(int pos);
598+
599+
Type getParameterType(int pos, TypePath path) {
600+
result = this.getParameterTypeRepr(pos).(TypeMention).getTypeAt(path)
601+
}
602+
603+
Type getReturnType(TypePath path) {
604+
result = TDataType(this.getTypeItem()) and
605+
path.isEmpty()
606+
or
607+
result = TTypeParamTypeParameter(this.getTypeItem().getGenericParamList().getATypeParam()) and
608+
path = TypePath::singleton(result)
609+
}
610+
}
611+
612+
private class StructConstructor extends ConstructorImpl instanceof Struct {
613+
override TypeItem getTypeItem() { result = this }
614+
615+
override TypeRepr getParameterTypeRepr(int i) {
616+
result = [super.getTupleField(i).getTypeRepr(), super.getNthStructField(i).getTypeRepr()]
617+
}
618+
}
619+
620+
private class VariantConstructor extends ConstructorImpl instanceof Variant {
621+
override TypeItem getTypeItem() { result = super.getEnum() }
622+
623+
override TypeRepr getParameterTypeRepr(int i) {
624+
result = [super.getTupleField(i).getTypeRepr(), super.getNthStructField(i).getTypeRepr()]
625+
}
626+
}
627+
628+
abstract class Construction extends Expr {
629+
abstract Constructor getTarget();
630+
631+
abstract AstNode getArgument(int i);
632+
633+
abstract Type getTypeArgument(TypeArgumentPosition apos, TypePath path);
634+
635+
/**
636+
* Holds if the return type of this construction expression at `path` may
637+
* have to be inferred from the context. For example in `Result::Ok(42)` the
638+
* error type has to be inferred from the context.
639+
*/
640+
pragma[nomagic]
641+
predicate hasUnknownReturnTypeAt(TypePath path) {
642+
exists(Constructor c, TypeParameter tp |
643+
c = this.getTarget() and
644+
tp = c.getReturnType(path) and
645+
not tp = c.getParameterType(_, _) and
646+
// check that no explicit type arguments have been supplied for `tp`
647+
not exists(TypeArgumentPosition tapos |
648+
this.getTypeArgument(tapos, _) != TUnknownType() and
649+
TTypeParamTypeParameter(tapos.asTypeParam()) = tp
650+
)
651+
)
652+
}
653+
}
654+
655+
private class NonAssocCallConstruction extends Construction, NonAssocCallExpr,
656+
ContextualTyping::ContextuallyTypedCallCand
657+
{
658+
NonAssocCallConstruction() {
659+
this instanceof CallExprImpl::TupleStructExpr or
660+
this instanceof CallExprImpl::TupleVariantExpr
661+
}
662+
663+
override Type getTypeArgument(TypeArgumentPosition apos, TypePath path) {
664+
result = NonAssocCallExpr.super.getTypeArgument(apos, path)
665+
}
666+
667+
override AstNode getArgument(int i) {
668+
exists(FunctionPosition pos |
669+
i = pos.asPosition() and
670+
result = NonAssocCallExpr.super.getNodeAt(pos)
671+
)
672+
}
673+
674+
override Constructor getTarget() { result = this.resolveCallTargetViaPathResolution() }
675+
}
676+
677+
abstract private class StructConstruction extends Construction instanceof PathAstNode {
678+
pragma[nomagic]
679+
override Constructor getTarget() { result = resolvePath(super.getPath()) }
680+
681+
pragma[nomagic]
682+
override Type getTypeArgument(TypeArgumentPosition apos, TypePath path) {
683+
// Handle constructions that use `Self {...}` syntax
684+
exists(TypeMention tm, TypePath path0 |
685+
tm = super.getPath() and
686+
result = tm.getTypeAt(path0) and
687+
path0.isCons(TTypeParamTypeParameter(apos.asTypeParam()), path)
688+
)
689+
}
690+
}
691+
692+
private class StructExprConstruction extends StructConstruction, StructExpr {
693+
override Type getTypeArgument(TypeArgumentPosition apos, TypePath path) {
694+
result = super.getTypeArgument(apos, path)
695+
or
696+
exists(TypePath suffix |
697+
suffix.isCons(TTypeParamTypeParameter(apos.asTypeParam()), path) and
698+
result = inferTypeCertain(this, suffix)
699+
)
700+
}
701+
702+
override AstNode getArgument(int i) {
703+
result =
704+
this.getFieldExpr(pragma[only_bind_into](this.getNthStructField(i).getName().getText()))
705+
.getExpr()
706+
}
707+
}
708+
709+
/** A potential nullary struct/variant construction such as `None`. */
710+
private class PathExprConstruction extends StructConstruction, PathExpr {
711+
PathExprConstruction() { not exists(CallExpr ce | this = ce.getFunction()) }
712+
713+
override AstNode getArgument(int i) { none() }
714+
}
715+
585716
predicate inferStepCertain(AstNode n1, TypePath path1, AstNode n2, TypePath path2) {
586717
n1 =
587718
any(IdentPat ip |
@@ -756,8 +887,6 @@ private module Input3 implements InputSig3 {
756887
or
757888
result = inferAssignmentOperationType(n, path)
758889
or
759-
exists(FunctionPosition pos | pos.isReturn() | result = inferConstructionType(n, pos, path))
760-
or
761890
result = inferTryExprType(n, path)
762891
or
763892
result = inferLiteralType(n, path, false)
@@ -776,10 +905,6 @@ private module Input3 implements InputSig3 {
776905
or
777906
result = inferUnknownType(n, path)
778907
}
779-
780-
Type inferTypeTopDown(AstNode n, TypePath path) {
781-
exists(FunctionPosition pos | not pos.isReturn() | result = inferConstructionType(n, pos, path))
782-
}
783908
}
784909

785910
private module M3 = Make3<Input3>;
@@ -3008,172 +3133,6 @@ private Type inferFunctionCallSelfArgumentTypeContextual(
30083133
)
30093134
}
30103135

3011-
abstract private class Constructor extends Addressable {
3012-
final TypeParameter getTypeParameter(TypeParameterPosition ppos) {
3013-
result = ppos.asTypeParameter() and
3014-
ppos.asTypeParam() = this.getTypeItem().getGenericParamList().getATypeParam()
3015-
}
3016-
3017-
abstract TypeItem getTypeItem();
3018-
3019-
abstract TypeRepr getParameterTypeRepr(int pos);
3020-
3021-
Type getParameterType(int pos, TypePath path) {
3022-
result = this.getParameterTypeRepr(pos).(TypeMention).getTypeAt(path)
3023-
}
3024-
3025-
Type getReturnType(TypePath path) {
3026-
result = TDataType(this.getTypeItem()) and
3027-
path.isEmpty()
3028-
or
3029-
result = TTypeParamTypeParameter(this.getTypeItem().getGenericParamList().getATypeParam()) and
3030-
path = TypePath::singleton(result)
3031-
}
3032-
3033-
Type getDeclaredType(FunctionPosition pos, TypePath path) {
3034-
result = this.getParameterType(pos.asPosition(), path)
3035-
or
3036-
pos.isReturn() and
3037-
result = this.getReturnType(path)
3038-
}
3039-
}
3040-
3041-
private class StructConstructor extends Constructor instanceof Struct {
3042-
override TypeItem getTypeItem() { result = this }
3043-
3044-
override TypeRepr getParameterTypeRepr(int i) {
3045-
result = [super.getTupleField(i).getTypeRepr(), super.getNthStructField(i).getTypeRepr()]
3046-
}
3047-
}
3048-
3049-
private class VariantConstructor extends Constructor instanceof Variant {
3050-
override TypeItem getTypeItem() { result = super.getEnum() }
3051-
3052-
override TypeRepr getParameterTypeRepr(int i) {
3053-
result = [super.getTupleField(i).getTypeRepr(), super.getNthStructField(i).getTypeRepr()]
3054-
}
3055-
}
3056-
3057-
/**
3058-
* A matching configuration for resolving types of constructions of enums and
3059-
* structs, such as `Result::Ok(42)`, `Foo { bar: 1 }` and `None`.
3060-
*/
3061-
private module ConstructionMatchingInput implements MatchingInputSig {
3062-
import FunctionPositionMatchingInput
3063-
3064-
class Declaration = Constructor;
3065-
3066-
abstract class Access extends AstNode {
3067-
abstract Type getInferredType(FunctionPosition pos, TypePath path);
3068-
3069-
abstract Declaration getTarget();
3070-
3071-
abstract AstNode getNodeAt(AccessPosition apos);
3072-
3073-
abstract Type getTypeArgument(TypeArgumentPosition apos, TypePath path);
3074-
3075-
/**
3076-
* Holds if the return type of this construction expression at `path` may
3077-
* have to be inferred from the context. For example in `Result::Ok(42)` the
3078-
* error type has to be inferred from the context.
3079-
*/
3080-
pragma[nomagic]
3081-
predicate hasUnknownTypeAt(FunctionPosition pos, TypePath path) {
3082-
exists(Declaration d, TypeParameter tp |
3083-
d = this.getTarget() and
3084-
pos.isReturn() and
3085-
tp = d.getReturnType(path) and
3086-
not exists(FunctionPosition pos2 | not pos2.isReturn() and tp = d.getDeclaredType(pos2, _)) and
3087-
// check that no explicit type arguments have been supplied for `tp`
3088-
not exists(TypeArgumentPosition tapos |
3089-
this.getTypeArgument(tapos, _) != TUnknownType() and
3090-
TTypeParamTypeParameter(tapos.asTypeParam()) = tp
3091-
)
3092-
)
3093-
}
3094-
}
3095-
3096-
private class NonAssocCallAccess extends Access, NonAssocCallExpr,
3097-
ContextualTyping::ContextuallyTypedCallCand
3098-
{
3099-
NonAssocCallAccess() {
3100-
this instanceof CallExprImpl::TupleStructExpr or
3101-
this instanceof CallExprImpl::TupleVariantExpr
3102-
}
3103-
3104-
override Type getTypeArgument(TypeArgumentPosition apos, TypePath path) {
3105-
result = NonAssocCallExpr.super.getTypeArgument(apos, path)
3106-
}
3107-
3108-
override AstNode getNodeAt(AccessPosition apos) {
3109-
result = NonAssocCallExpr.super.getNodeAt(apos)
3110-
}
3111-
3112-
override Type getInferredType(FunctionPosition pos, TypePath path) {
3113-
result = NonAssocCallExpr.super.getInferredType(pos, path)
3114-
}
3115-
3116-
override Declaration getTarget() { result = this.resolveCallTargetViaPathResolution() }
3117-
}
3118-
3119-
abstract private class StructAccess extends Access instanceof PathAstNode {
3120-
pragma[nomagic]
3121-
override Type getInferredType(AccessPosition apos, TypePath path) {
3122-
result = inferType(this.getNodeAt(apos), path)
3123-
}
3124-
3125-
pragma[nomagic]
3126-
override Declaration getTarget() { result = resolvePath(super.getPath()) }
3127-
3128-
pragma[nomagic]
3129-
override Type getTypeArgument(TypeArgumentPosition apos, TypePath path) {
3130-
// Handle constructions that use `Self {...}` syntax
3131-
exists(TypeMention tm, TypePath path0 |
3132-
tm = super.getPath() and
3133-
result = tm.getTypeAt(path0) and
3134-
path0.isCons(TTypeParamTypeParameter(apos.asTypeParam()), path)
3135-
)
3136-
}
3137-
}
3138-
3139-
private class StructExprAccess extends StructAccess, StructExpr {
3140-
override Type getTypeArgument(TypeArgumentPosition apos, TypePath path) {
3141-
result = super.getTypeArgument(apos, path)
3142-
or
3143-
exists(TypePath suffix |
3144-
suffix.isCons(TTypeParamTypeParameter(apos.asTypeParam()), path) and
3145-
result = inferTypeCertain(this, suffix)
3146-
)
3147-
}
3148-
3149-
override AstNode getNodeAt(AccessPosition apos) {
3150-
result =
3151-
this.getFieldExpr(pragma[only_bind_into](this.getNthStructField(apos.asPosition())
3152-
.getName()
3153-
.getText())).getExpr()
3154-
or
3155-
result = this and apos.isReturn()
3156-
}
3157-
}
3158-
3159-
/** A potential nullary struct/variant construction such as `None`. */
3160-
private class PathExprAccess extends StructAccess, PathExpr {
3161-
PathExprAccess() { not exists(CallExpr ce | this = ce.getFunction()) }
3162-
3163-
override AstNode getNodeAt(AccessPosition apos) { result = this and apos.isReturn() }
3164-
}
3165-
}
3166-
3167-
private module ConstructionMatching = Matching<ConstructionMatchingInput>;
3168-
3169-
pragma[nomagic]
3170-
private Type inferConstructionType(AstNode n, FunctionPosition pos, TypePath path) {
3171-
exists(ConstructionMatchingInput::Access a |
3172-
n = a.getNodeAt(pos) and
3173-
result = ConstructionMatching::inferAccessType(a, pos, path)
3174-
)
3175-
}
3176-
31773136
pragma[nomagic]
31783137
private Type inferUnknownType(AstNode n, TypePath path) {
31793138
result = TUnknownType() and
@@ -3183,10 +3142,7 @@ private Type inferUnknownType(AstNode n, TypePath path) {
31833142
call.hasUnknownTypeAt(_, pos, path)
31843143
)
31853144
or
3186-
exists(ConstructionMatchingInput::Access a, FunctionPosition pos |
3187-
n = a.getNodeAt(pos) and
3188-
a.hasUnknownTypeAt(pos, path)
3189-
)
3145+
n.(Input3::Construction).hasUnknownReturnTypeAt(path)
31903146
or
31913147
exists(Param p |
31923148
not p.hasTypeRepr() and
@@ -3452,7 +3408,14 @@ private Type inferDereferencedExprPtrType(AstNode n, TypePath path) {
34523408
private module DeconstructionPatMatchingInput implements MatchingInputSig {
34533409
import FunctionPositionMatchingInput
34543410

3455-
class Declaration = ConstructionMatchingInput::Declaration;
3411+
class Declaration extends Input3::Constructor {
3412+
Type getDeclaredType(FunctionPosition pos, TypePath path) {
3413+
result = this.getParameterType(pos.asPosition(), path)
3414+
or
3415+
pos.isReturn() and
3416+
result = this.getReturnType(path)
3417+
}
3418+
}
34563419

34573420
class Access extends Pat instanceof PathAstNode {
34583421
Access() { this instanceof TupleStructPat or this instanceof StructPat }

0 commit comments

Comments
 (0)