Rust: Implement await expression using SatisfiesConstraint module

This commit is contained in:
Simon Friis Vindum
2025-06-20 13:53:29 +02:00
parent a367388326
commit 6e9fd496a6
3 changed files with 18 additions and 86 deletions

View File

@@ -1132,7 +1132,7 @@ pragma[nomagic]
private predicate crateDependencyEdge(SourceFileItemNode file, string name, CrateItemNode dep) {
exists(CrateItemNode c | dep = c.(Crate).getDependency(name) | file = c.getASourceFile())
or
// Give builtin files, such as `await.rs`, access to `std`
// Give builtin files access to `std`
file instanceof BuiltinSourceFile and
dep.getName() = name and
name = "std"
@@ -1501,7 +1501,7 @@ private predicate preludeEdge(SourceFile f, string name, ItemNode i) {
exists(Crate stdOrCore, ModuleLikeNode mod, ModuleItemNode prelude, ModuleItemNode rust |
f = any(Crate c0 | stdOrCore = c0.getDependency(_) or stdOrCore = c0).getASourceFile()
or
// Give builtin files, such as `await.rs`, access to the prelude
// Give builtin files access to the prelude
f instanceof BuiltinSourceFile
|
stdOrCore.getName() = ["std", "core"] and

View File

@@ -997,79 +997,6 @@ private AssociatedTypeTypeParameter getFutureOutputTypeParameter() {
result.getTypeAlias() = any(FutureTrait ft).getOutputType()
}
/**
* A matching configuration for resolving types of `.await` expressions.
*/
private module AwaitExprMatchingInput implements MatchingInputSig {
private newtype TDeclarationPosition =
TSelfDeclarationPosition() or
TOutputPos()
class DeclarationPosition extends TDeclarationPosition {
predicate isSelf() { this = TSelfDeclarationPosition() }
predicate isOutput() { this = TOutputPos() }
string toString() {
this.isSelf() and
result = "self"
or
this.isOutput() and
result = "(output)"
}
}
private class BuiltinsAwaitFile extends File {
BuiltinsAwaitFile() {
this.getBaseName() = "await.rs" and
this.getParentContainer() instanceof Builtins::BuiltinsFolder
}
}
class Declaration extends Function {
Declaration() {
this.getFile() instanceof BuiltinsAwaitFile and
this.getName().getText() = "await_type_matching"
}
TypeParameter getTypeParameter(TypeParameterPosition ppos) {
typeParamMatchPosition(this.getGenericParamList().getATypeParam(), result, ppos)
}
Type getDeclaredType(DeclarationPosition dpos, TypePath path) {
dpos.isSelf() and
result = this.getParam(0).getTypeRepr().(TypeMention).resolveTypeAt(path)
or
dpos.isOutput() and
result = this.getRetType().getTypeRepr().(TypeMention).resolveTypeAt(path)
}
}
class AccessPosition = DeclarationPosition;
class Access extends AwaitExpr {
Type getTypeArgument(TypeArgumentPosition apos, TypePath path) { none() }
AstNode getNodeAt(AccessPosition apos) {
result = this.getExpr() and
apos.isSelf()
or
result = this and
apos.isOutput()
}
Type getInferredType(AccessPosition apos, TypePath path) {
result = inferType(this.getNodeAt(apos), path)
}
Declaration getTarget() { exists(this) and exists(result) }
}
predicate accessDeclarationPositionMatch(AccessPosition apos, DeclarationPosition dpos) {
apos = dpos
}
}
pragma[nomagic]
private TraitType inferAsyncBlockExprRootType(AsyncBlockExpr abe) {
// `typeEquality` handles the non-root case
@@ -1077,13 +1004,25 @@ private TraitType inferAsyncBlockExprRootType(AsyncBlockExpr abe) {
result = getFutureTraitType()
}
private module AwaitExprMatching = Matching<AwaitExprMatchingInput>;
final class AwaitTarget extends Expr {
AwaitTarget() { this = any(AwaitExpr ae).getExpr() }
Type getTypeAt(TypePath path) { result = inferType(this, path) }
}
private module AwaitSatisfiesConstraintInput implements SatisfiesConstraintSig<AwaitTarget> {
predicate relevantConstraint(AwaitTarget term, Type constraint) {
exists(term) and
constraint.(TraitType).getTrait() instanceof FutureTrait
}
}
pragma[nomagic]
private Type inferAwaitExprType(AstNode n, TypePath path) {
exists(AwaitExprMatchingInput::Access a, AwaitExprMatchingInput::AccessPosition apos |
n = a.getNodeAt(apos) and
result = AwaitExprMatching::inferAccessType(a, apos, path)
exists(TypePath exprPath |
SatisfiesConstraint<AwaitTarget, AwaitSatisfiesConstraintInput>::satisfiesConstraintTypeMention(n.(AwaitExpr)
.getExpr(), _, exprPath, result) and
exprPath.isCons(getFutureOutputTypeParameter(), path)
)
or
// This case is needed for `async` functions and blocks, where we assign

View File

@@ -1,7 +0,0 @@
use std::future::Future;
fn await_type_matching<T1, T2: Future<Output = T1>>(x: T2) -> T1 {
panic!(
"This function exists only in order to implement type inference for `.await` expressions."
);
}