summaryrefslogtreecommitdiffstats
path: root/source/slang/check.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/slang/check.cpp')
-rw-r--r--source/slang/check.cpp164
1 files changed, 135 insertions, 29 deletions
diff --git a/source/slang/check.cpp b/source/slang/check.cpp
index 38a79f1b7..7c60d3cf2 100644
--- a/source/slang/check.cpp
+++ b/source/slang/check.cpp
@@ -561,6 +561,80 @@ namespace Slang
return isDeclUsableAsStaticMember(decl);
}
+ RefPtr<Expr> maybeOpenExistential(RefPtr<Expr> expr)
+ {
+ auto exprType = expr->type.type;
+
+ if(auto declRefType = exprType->As<DeclRefType>())
+ {
+ if(auto interfaceDeclRef = declRefType->declRef.As<InterfaceDecl>())
+ {
+ // Is there an this-type substitution being applied, so that
+ // we are referencing the interface type through a concrete
+ // type (e.g., a type parameter constrainted to this interface)?
+ //
+ // Because of the way that substitutions need to mirror the nesting
+ // hierarchy of declarations, any this-type substitution pertaining
+ // to the chosen interface decl must be the first substitution on
+ // the list (which is a linked list from the "inside" out).
+ //
+ auto thisTypeSubst = interfaceDeclRef.substitutions.substitutions.As<ThisTypeSubstitution>();
+ if(thisTypeSubst && thisTypeSubst->interfaceDecl == interfaceDeclRef.decl)
+ {
+ // This isn't really an existential type, because somebody
+ // has already filled in a this-type substitution.
+ }
+ else
+ {
+ // Okay, here is the case that matters.
+ //
+
+ auto interfaceDecl = interfaceDeclRef.getDecl();
+
+ RefPtr<Variable> varDecl = new Variable();
+ varDecl->ParentDecl = nullptr; // TODO: need to fill this in somehow!
+ varDecl->checkState = DeclCheckState::Checked;
+ varDecl->nameAndLoc.loc = expr->loc;
+ varDecl->initExpr = expr;
+ varDecl->type.type = expr->type.type;
+
+ auto varDeclRef = makeDeclRef(varDecl.Ptr());
+
+ RefPtr<LetExpr> letExpr = new LetExpr();
+ letExpr->decl = varDecl;
+
+ RefPtr<ExtractExistentialType> openedType = new ExtractExistentialType();
+ openedType->declRef = varDeclRef;
+
+ RefPtr<ExtractExistentialSubtypeWitness> openedWitness = new ExtractExistentialSubtypeWitness();
+ openedWitness->sub = openedType;
+ openedWitness->sup = expr->type.type;
+ openedWitness->declRef = varDeclRef;
+
+ RefPtr<ThisTypeSubstitution> openedThisType = new ThisTypeSubstitution();
+ openedThisType->outer = interfaceDeclRef.substitutions.substitutions;
+ openedThisType->interfaceDecl = interfaceDecl;
+ openedThisType->witness = openedWitness;
+
+ DeclRef<InterfaceDecl> substDeclRef = DeclRef<InterfaceDecl>(interfaceDecl, openedThisType);
+ auto substDeclRefType = DeclRefType::Create(getSession(), substDeclRef);
+
+ RefPtr<ExtractExistentialValueExpr> openedValue = new ExtractExistentialValueExpr();
+ openedValue->declRef = varDeclRef;
+ openedValue->type = QualType(substDeclRefType);
+
+ letExpr->body = openedValue;
+ letExpr->type = openedValue->type;
+
+ return letExpr;
+ }
+ }
+ }
+
+ // Default: apply the callback to the original expression;
+ return expr;
+ }
+
RefPtr<Expr> ConstructDeclRefExpr(
DeclRef<Decl> declRef,
RefPtr<Expr> baseExpr,
@@ -577,6 +651,15 @@ namespace Slang
{
// If there was a base expression, we will have some kind of
// member expression.
+
+ // We want to check for the case where the base "expression"
+ // actually names a type, because in that case we are doing
+ // a static member reference.
+ //
+ // TODO: Should we be checking if the member is static here?
+ // If it isn't, should we be automatically producing a "curried"
+ // form (e.g., for a member function, return a value usable
+ // for referencing it as a free function).
//
if (baseExpr->type->As<TypeType>())
{
@@ -1440,15 +1523,22 @@ namespace Slang
// Trying to convert to an interface type.
//
// We will allow this if the type conforms to the interface.
- if (DoesTypeConformToInterface(fromType, interfaceDeclRef))
+
+ if(auto witness = tryGetInterfaceConformanceWitness(fromType, interfaceDeclRef))
{
if (outToExpr)
- *outToExpr = CreateImplicitCastExpr(toType, fromExpr);
+ *outToExpr = createCastToInterfaceExpr(toType, fromExpr, witness);
if (outCost)
*outCost = kConversionCost_CastToInterface;
return true;
}
}
+
+ // Note: The following seems completely broken, and we should be using
+ // a `fromTypeDeclRef` here for the case when casting *from* a generic
+ // type parameter to an interface type...
+ //
+#if 0
else if (auto genParamDeclRef = toTypeDeclRef.As<GenericTypeParamDecl>())
{
// We need to enumerate the constraints placed on this type by its outer
@@ -1483,6 +1573,7 @@ namespace Slang
}
}
+#endif
}
@@ -1721,6 +1812,25 @@ namespace Slang
return castExpr;
}
+ /// Create an "up-cast" from a value to an interface type
+ ///
+ /// This operation logically constructs an "existential" value,
+ /// which packages up the value, its type, and the witness
+ /// of its conformance to the interface.
+ ///
+ RefPtr<Expr> createCastToInterfaceExpr(
+ RefPtr<Type> toType,
+ RefPtr<Expr> fromExpr,
+ RefPtr<Val> witness)
+ {
+ RefPtr<CastToInterfaceExpr> expr = new CastToInterfaceExpr();
+ expr->loc = fromExpr->loc;
+ expr->type = QualType(toType);
+ expr->valueArg = fromExpr;
+ expr->witnessArg = witness;
+ return expr;
+ }
+
// Perform type coercion, and emit errors if it isn't possible
RefPtr<Expr> Coerce(
RefPtr<Type> toType,
@@ -7900,36 +8010,24 @@ namespace Slang
// deal with this cases here, even if they are no-ops.
//
- RefPtr<Expr> visitDerefExpr(DerefExpr* expr)
- {
- SLANG_DIAGNOSE_UNEXPECTED(getSink(), expr, "should not appear in input syntax");
- return expr;
+ #define CASE(NAME) \
+ RefPtr<Expr> visit##NAME(NAME* expr) \
+ { \
+ SLANG_DIAGNOSE_UNEXPECTED(getSink(), expr, \
+ "should not appear in input syntax"); \
+ return expr; \
}
- RefPtr<Expr> visitSwizzleExpr(SwizzleExpr* expr)
- {
- SLANG_DIAGNOSE_UNEXPECTED(getSink(), expr, "should not appear in input syntax");
- return expr;
- }
+ CASE(DerefExpr)
+ CASE(SwizzleExpr)
+ CASE(OverloadedExpr)
+ CASE(OverloadedExpr2)
+ CASE(AggTypeCtorExpr)
+ CASE(CastToInterfaceExpr)
+ CASE(LetExpr)
+ CASE(ExtractExistentialValueExpr)
- RefPtr<Expr> visitOverloadedExpr(OverloadedExpr* expr)
- {
- SLANG_DIAGNOSE_UNEXPECTED(getSink(), expr, "should not appear in input syntax");
- return expr;
- }
-
- RefPtr<Expr> visitOverloadedExpr2(OverloadedExpr2* expr)
- {
- SLANG_DIAGNOSE_UNEXPECTED(getSink(), expr, "should not appear in input syntax");
- return expr;
- }
-
-
- RefPtr<Expr> visitAggTypeCtorExpr(AggTypeCtorExpr* expr)
- {
- SLANG_DIAGNOSE_UNEXPECTED(getSink(), expr, "should not appear in input syntax");
- return expr;
- }
+ #undef CASE
//
//
@@ -8091,6 +8189,14 @@ namespace Slang
expr->BaseExpression = MaybeDereference(expr->BaseExpression);
+ // If the base of the member lookup has an interface type
+ // *without* a suitable this-type substitution, then we are
+ // trying to perform lookup on a value of existential type,
+ // and we should "open" the existential here so that we
+ // can expose its structure.
+ //
+ expr->BaseExpression = maybeOpenExistential(expr->BaseExpression);
+
auto & baseType = expr->BaseExpression->type;
// Note: Checking for vector types before declaration-reference types,