summaryrefslogtreecommitdiffstats
path: root/source
diff options
context:
space:
mode:
authorTim Foley <tfoleyNV@users.noreply.github.com>2020-02-21 10:39:05 -0800
committerGitHub <noreply@github.com>2020-02-21 10:39:05 -0800
commit830671c2210191f69ddc403cc12f5454bb55b0f0 (patch)
treebc242d34920715c33c827f4071d1ca8a1994a6b6 /source
parent433ce869481b72ad44897dcc91d7038b03ba45e2 (diff)
Add surface syntax for "this type" (#1236)
Within the context of an aggregate type (or an `extension` of one), the programmer can use `this` to refer to the "current" instance of the surrounding type, but there is no easy way to utter the name of the type itself. This is especially relevant inside of an `interface`, where the type of `this` isn't actually the `interface` type, but rather a placeholder for the as-yet-unknown concrete type that will implement the interface. This change adds a keyword `This` that works similarly to `this`, but names the current *type* instead of the current instance. It can be used to declare things like binary methods or factory functions in an interface: ``` interface IBasicMathType { This absoluteValue(); This sumWith(This left); } T doSomeMath<T:IBasicMathType>(T value) { return value.sumWith(value.absoluteValue()); } ``` The `This` type is consistent with the type named `Self` in Rust and Swift (where Rust/Swift use `self` instead of `this`). Other names could be considered (e.g., `ThisType`) if we find that users don't like the name in this change.
Diffstat (limited to 'source')
-rw-r--r--source/slang/slang-check-expr.cpp30
-rw-r--r--source/slang/slang-check-impl.h1
-rw-r--r--source/slang/slang-diagnostic-defs.h1
-rw-r--r--source/slang/slang-expr-defs.h8
-rw-r--r--source/slang/slang-lower-to-ir.cpp6
-rw-r--r--source/slang/slang-mangle.cpp5
-rw-r--r--source/slang/slang-parser.cpp19
7 files changed, 70 insertions, 0 deletions
diff --git a/source/slang/slang-check-expr.cpp b/source/slang/slang-check-expr.cpp
index ebc3a3ef9..524bab4e4 100644
--- a/source/slang/slang-check-expr.cpp
+++ b/source/slang/slang-check-expr.cpp
@@ -1677,6 +1677,12 @@ namespace Slang
expr->type.IsLeftValue = true;
}
}
+ else if( auto typeOrExtensionDecl = as<AggTypeDeclBase>(containerDecl) )
+ {
+ expr->type.type = calcThisType(makeDeclRef(typeOrExtensionDecl));
+ return expr;
+ }
+#if 0
else if (auto aggTypeDecl = as<AggTypeDecl>(containerDecl))
{
ensureDecl(aggTypeDecl, DeclCheckState::CanUseAsType);
@@ -1706,6 +1712,7 @@ namespace Slang
expr->type.type = extensionDecl->targetType.type;
return expr;
}
+#endif
scope = scope->parent;
}
@@ -1713,4 +1720,27 @@ namespace Slang
getSink()->diagnose(expr, Diagnostics::thisExpressionOutsideOfTypeDecl);
return CreateErrorExpr(expr);
}
+
+ RefPtr<Expr> SemanticsExprVisitor::visitThisTypeExpr(ThisTypeExpr* expr)
+ {
+ auto scope = expr->scope;
+ while (scope)
+ {
+ auto containerDecl = scope->containerDecl;
+ if( auto typeOrExtensionDecl = as<AggTypeDeclBase>(containerDecl) )
+ {
+ auto thisType = calcThisType(makeDeclRef(typeOrExtensionDecl));
+ auto thisTypeType = getTypeType(thisType);
+
+ expr->type.type = thisTypeType;
+ return expr;
+ }
+
+ scope = scope->parent;
+ }
+
+ getSink()->diagnose(expr, Diagnostics::thisTypeOutsideOfTypeDecl);
+ return CreateErrorExpr(expr);
+ }
+
}
diff --git a/source/slang/slang-check-impl.h b/source/slang/slang-check-impl.h
index 764f0526a..9363066d1 100644
--- a/source/slang/slang-check-impl.h
+++ b/source/slang/slang-check-impl.h
@@ -1363,6 +1363,7 @@ namespace Slang
RefPtr<Expr> visitInitializerListExpr(InitializerListExpr* expr);
RefPtr<Expr> visitThisExpr(ThisExpr* expr);
+ RefPtr<Expr> visitThisTypeExpr(ThisTypeExpr* expr);
};
struct SemanticsStmtVisitor
diff --git a/source/slang/slang-diagnostic-defs.h b/source/slang/slang-diagnostic-defs.h
index 06031c089..8bcdb9a09 100644
--- a/source/slang/slang-diagnostic-defs.h
+++ b/source/slang/slang-diagnostic-defs.h
@@ -384,6 +384,7 @@ DIAGNOSTIC(38100, Error, typeDoesntImplementInterfaceRequirement, "type '$0' doe
DIAGNOSTIC(38101, Error, thisExpressionOutsideOfTypeDecl, "'this' expression can only be used in members of an aggregate type")
DIAGNOSTIC(38102, Error, initializerNotInsideType, "an 'init' declaration is only allowed inside a type or 'extension' declaration")
DIAGNOSTIC(38102, Error, accessorMustBeInsideSubscriptOrProperty, "an accessor declaration is only allowed inside a subscript or property declaration")
+DIAGNOSTIC(38103, Error, thisTypeOutsideOfTypeDecl, "'This' type can only be used inside of an aggregate type")
DIAGNOSTIC(38020, Error, mismatchEntryPointTypeArgument, "expecting $0 entry-point type arguments, provided $1.")
DIAGNOSTIC(38021, Error, typeArgumentForGenericParameterDoesNotConformToInterface, "type argument `$0` for generic parameter `$1` does not conform to interface `$2`.")
diff --git a/source/slang/slang-expr-defs.h b/source/slang/slang-expr-defs.h
index 6cd893302..a7105b07b 100644
--- a/source/slang/slang-expr-defs.h
+++ b/source/slang/slang-expr-defs.h
@@ -204,3 +204,11 @@ RAW(
List<TypeExp> caseTypes;
)
END_SYNTAX_CLASS()
+
+ /// A type expression of the form `This`
+ ///
+ /// Refers to the type of `this` in the current context.
+ ///
+SYNTAX_CLASS(ThisTypeExpr, Expr)
+ FIELD(RefPtr<Scope>, scope);
+END_SYNTAX_CLASS()
diff --git a/source/slang/slang-lower-to-ir.cpp b/source/slang/slang-lower-to-ir.cpp
index 360376b73..3cd3f73e3 100644
--- a/source/slang/slang-lower-to-ir.cpp
+++ b/source/slang/slang-lower-to-ir.cpp
@@ -3004,6 +3004,12 @@ struct ExprLoweringVisitorBase : ExprVisitor<Derived, LoweredValInfo>
UNREACHABLE_RETURN(LoweredValInfo());
}
+ LoweredValInfo visitThisTypeExpr(ThisTypeExpr* /*expr*/)
+ {
+ SLANG_UNIMPLEMENTED_X("this-type expression during code generation");
+ UNREACHABLE_RETURN(LoweredValInfo());
+ }
+
LoweredValInfo visitAssignExpr(AssignExpr* expr)
{
// Because our representation of lowered "values"
diff --git a/source/slang/slang-mangle.cpp b/source/slang/slang-mangle.cpp
index fbeb5c9bf..5d9320f3d 100644
--- a/source/slang/slang-mangle.cpp
+++ b/source/slang/slang-mangle.cpp
@@ -151,6 +151,11 @@ namespace Slang
}
emitRaw(context, "U");
}
+ else if( auto thisType = dynamicCast<ThisType>(type) )
+ {
+ emitRaw(context, "t");
+ emitQualifiedName(context, thisType->interfaceDeclRef);
+ }
else
{
SLANG_UNEXPECTED("unimplemented case in mangling");
diff --git a/source/slang/slang-parser.cpp b/source/slang/slang-parser.cpp
index e5a1ad576..288962cd8 100644
--- a/source/slang/slang-parser.cpp
+++ b/source/slang/slang-parser.cpp
@@ -1794,6 +1794,19 @@ namespace Slang
return parseTaggedUnionType(parser);
}
+ /// Parse a `This` type expression
+ static RefPtr<Expr> parseThisTypeExpr(Parser* parser)
+ {
+ RefPtr<ThisTypeExpr> expr = new ThisTypeExpr();
+ expr->scope = parser->currentScope;
+ return expr;
+ }
+
+ static RefPtr<RefObject> parseThisTypeExpr(Parser* parser, void* /*userData*/)
+ {
+ return parseThisTypeExpr(parser);
+ }
+
static TypeSpec parseTypeSpec(Parser* parser)
{
TypeSpec typeSpec;
@@ -1848,6 +1861,11 @@ namespace Slang
typeSpec.expr = parseTaggedUnionType(parser);
return typeSpec;
}
+ else if(AdvanceIf(parser, "This"))
+ {
+ typeSpec.expr = parseThisTypeExpr(parser);
+ return typeSpec;
+ }
Token typeName = parser->ReadToken(TokenType::Identifier);
@@ -4995,6 +5013,7 @@ namespace Slang
addBuiltinSyntax<Expr>(session, scope, #KEYWORD, &CALLBACK)
EXPR(this, parseThisExpr);
+ EXPR(This, parseThisTypeExpr);
EXPR(true, parseTrueExpr);
EXPR(false, parseFalseExpr);
EXPR(__TaggedUnion, parseTaggedUnionType);