resolver: Replace ICEs with proper errors
If you attempted to: * Use a function as a type * Use a variable as a type * Use a variable as a call target You would get an ICE. Replace these with proper error diagnostics. Change-Id: Ibbe4cd1b59b1aadd451aa0445ad137859aa071eb Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/79765 Reviewed-by: James Price <jrprice@google.com> Kokoro: Kokoro <noreply+kokoro@google.com> Commit-Queue: Ben Clayton <bclayton@google.com>
This commit is contained in:
parent
88d1a433aa
commit
597fc4cdbe
|
@ -252,6 +252,19 @@ TEST_F(ResolverCallValidationTest, LetPointerPrivate) {
|
|||
"identifier expression or a function parameter");
|
||||
}
|
||||
|
||||
TEST_F(ResolverCallValidationTest, CallVariable) {
|
||||
// var v : i32;
|
||||
// fn f() {
|
||||
// v();
|
||||
// }
|
||||
Global("v", ty.i32(), ast::StorageClass::kPrivate);
|
||||
Func("f", {}, ty.void_(), {CallStmt(Call(Source{{12, 34}}, "v"))});
|
||||
|
||||
EXPECT_FALSE(r()->Resolve());
|
||||
EXPECT_EQ(r()->error(), R"(error: cannot call variable 'v'
|
||||
note: 'v' declared here)");
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace resolver
|
||||
} // namespace tint
|
||||
|
|
|
@ -266,12 +266,26 @@ sem::Type* Resolver::Type(const ast::Type* ty) {
|
|||
if (ty->As<ast::ExternalTexture>()) {
|
||||
return builder_->create<sem::ExternalTexture>();
|
||||
}
|
||||
if (auto* type = ResolvedSymbol<sem::Type>(ty)) {
|
||||
return type;
|
||||
}
|
||||
TINT_UNREACHABLE(Resolver, diagnostics_)
|
||||
<< "Unhandled ast::Type: " << ty->TypeInfo().name;
|
||||
return nullptr;
|
||||
return Switch(
|
||||
ResolvedSymbol(ty), //
|
||||
[&](sem::Type* type) { return type; },
|
||||
[&](sem::Variable* var) {
|
||||
auto name = builder_->Symbols().NameFor(var->Declaration()->symbol);
|
||||
AddError("cannot use variable '" + name + "' as type", ty->source);
|
||||
AddNote("'" + name + "' declared here", var->Declaration()->source);
|
||||
return nullptr;
|
||||
},
|
||||
[&](sem::Function* func) {
|
||||
auto name = builder_->Symbols().NameFor(func->Declaration()->symbol);
|
||||
AddError("cannot use function '" + name + "' as type", ty->source);
|
||||
AddNote("'" + name + "' declared here", func->Declaration()->source);
|
||||
return nullptr;
|
||||
},
|
||||
[&](Default) {
|
||||
TINT_UNREACHABLE(Resolver, diagnostics_)
|
||||
<< "Unhandled ast::Type: " << ty->TypeInfo().name;
|
||||
return nullptr;
|
||||
});
|
||||
}();
|
||||
|
||||
if (s) {
|
||||
|
@ -1347,26 +1361,33 @@ sem::Call* Resolver::Call(const ast::CallExpression* expr) {
|
|||
Mark(ident);
|
||||
|
||||
auto* resolved = ResolvedSymbol(ident);
|
||||
if (auto* ty = As<sem::Type>(resolved)) {
|
||||
return type_ctor_or_conv(ty);
|
||||
}
|
||||
return Switch(
|
||||
resolved, //
|
||||
[&](sem::Type* type) { return type_ctor_or_conv(type); },
|
||||
[&](sem::Function* func) {
|
||||
return FunctionCall(expr, func, std::move(args), arg_behaviors);
|
||||
},
|
||||
[&](sem::Variable* var) {
|
||||
auto name = builder_->Symbols().NameFor(var->Declaration()->symbol);
|
||||
AddError("cannot call variable '" + name + "'", ident->source);
|
||||
AddNote("'" + name + "' declared here", var->Declaration()->source);
|
||||
return nullptr;
|
||||
},
|
||||
[&](Default) -> sem::Call* {
|
||||
auto name = builder_->Symbols().NameFor(ident->symbol);
|
||||
auto builtin_type = sem::ParseBuiltinType(name);
|
||||
if (builtin_type != sem::BuiltinType::kNone) {
|
||||
return BuiltinCall(expr, builtin_type, std::move(args),
|
||||
std::move(arg_tys));
|
||||
}
|
||||
|
||||
if (auto* fn = As<sem::Function>(resolved)) {
|
||||
return FunctionCall(expr, fn, std::move(args), arg_behaviors);
|
||||
}
|
||||
|
||||
auto name = builder_->Symbols().NameFor(ident->symbol);
|
||||
auto builtin_type = sem::ParseBuiltinType(name);
|
||||
if (builtin_type != sem::BuiltinType::kNone) {
|
||||
return BuiltinCall(expr, builtin_type, std::move(args), std::move(arg_tys));
|
||||
}
|
||||
|
||||
TINT_ICE(Resolver, diagnostics_)
|
||||
<< expr->source << " unresolved CallExpression target:\n"
|
||||
<< "resolved: " << (resolved ? resolved->TypeInfo().name : "<null>")
|
||||
<< "\n"
|
||||
<< "name: " << builder_->Symbols().NameFor(ident->symbol);
|
||||
return nullptr;
|
||||
TINT_ICE(Resolver, diagnostics_)
|
||||
<< expr->source << " unresolved CallExpression target:\n"
|
||||
<< "resolved: " << (resolved ? resolved->TypeInfo().name : "<null>")
|
||||
<< "\n"
|
||||
<< "name: " << builder_->Symbols().NameFor(ident->symbol);
|
||||
return nullptr;
|
||||
});
|
||||
}
|
||||
|
||||
sem::Call* Resolver::BuiltinCall(const ast::CallExpression* expr,
|
||||
|
|
|
@ -695,6 +695,30 @@ TEST_F(ResolverTypeValidationTest, ArrayOfNonStorableType) {
|
|||
"an array");
|
||||
}
|
||||
|
||||
TEST_F(ResolverTypeValidationTest, VariableAsType) {
|
||||
// var<private> a : i32;
|
||||
// var<private> b : a;
|
||||
Global("a", ty.i32(), ast::StorageClass::kPrivate);
|
||||
Global("b", ty.type_name("a"), ast::StorageClass::kPrivate);
|
||||
|
||||
EXPECT_FALSE(r()->Resolve());
|
||||
EXPECT_EQ(r()->error(),
|
||||
R"(error: cannot use variable 'a' as type
|
||||
note: 'a' declared here)");
|
||||
}
|
||||
|
||||
TEST_F(ResolverTypeValidationTest, FunctionAsType) {
|
||||
// fn f() {}
|
||||
// var<private> v : f;
|
||||
Func("f", {}, ty.void_(), {});
|
||||
Global("v", ty.type_name("f"), ast::StorageClass::kPrivate);
|
||||
|
||||
EXPECT_FALSE(r()->Resolve());
|
||||
EXPECT_EQ(r()->error(),
|
||||
R"(error: cannot use function 'f' as type
|
||||
note: 'f' declared here)");
|
||||
}
|
||||
|
||||
namespace GetCanonicalTests {
|
||||
struct Params {
|
||||
builder::ast_type_func_ptr create_ast_type;
|
||||
|
|
Loading…
Reference in New Issue