[torque] Unused implicit parameters can be undefined
e.g. the following is now valid Torque code: macro TestA(implicit c: Context)() {} macro TestB(): bool { return TestA(); } This is handy for more flexible usage of generics that may or may not use implicit parameters deep inside their specializations. Note that this change doesn't change the fundamental rigor (or lack thereof) around checking the usage of implicit parameters, which already do not require '_' before their parameter identifier if unused. It just silences errors in cases where a call site doesn't implicitly pass a parameter that ultimately doesn't have a use site and adds meaningful error messages in the case that it does. Bug: v8:7793 Change-Id: I559d06c0864a7e79fe52bee5a9a7af9941889748 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2274127 Commit-Queue: Daniel Clifford <danno@chromium.org> Reviewed-by: Tobias Tebbi <tebbi@chromium.org> Cr-Commit-Position: refs/heads/master@{#68618}
This commit is contained in:
parent
0d3e5872a1
commit
9bd8e5f247
@ -95,8 +95,12 @@ std::vector<Declarable*> Scope::Lookup(const QualifiedName& name) {
|
||||
|
||||
base::Optional<std::string> TypeConstraint::IsViolated(const Type* type) const {
|
||||
if (upper_bound && !type->IsSubtypeOf(*upper_bound)) {
|
||||
return {
|
||||
ToString("expected ", *type, " to be a subtype of ", **upper_bound)};
|
||||
if (type->IsTopType()) {
|
||||
return TopType::cast(type)->reason();
|
||||
} else {
|
||||
return {
|
||||
ToString("expected ", *type, " to be a subtype of ", **upper_bound)};
|
||||
}
|
||||
}
|
||||
return base::nullopt;
|
||||
}
|
||||
|
@ -2391,10 +2391,16 @@ VisitResult ImplementationVisitor::GeneratePointerCall(
|
||||
void ImplementationVisitor::AddCallParameter(
|
||||
Callable* callable, VisitResult parameter, const Type* parameter_type,
|
||||
std::vector<VisitResult>* converted_arguments, StackRange* argument_range,
|
||||
std::vector<std::string>* constexpr_arguments) {
|
||||
VisitResult converted = GenerateImplicitConvert(parameter_type, parameter);
|
||||
std::vector<std::string>* constexpr_arguments, bool inline_macro) {
|
||||
VisitResult converted;
|
||||
if ((converted_arguments->size() < callable->signature().implicit_count) &&
|
||||
parameter.type()->IsTopType()) {
|
||||
converted = GenerateCopy(parameter);
|
||||
} else {
|
||||
converted = GenerateImplicitConvert(parameter_type, parameter);
|
||||
}
|
||||
converted_arguments->push_back(converted);
|
||||
if (!callable->ShouldBeInlined()) {
|
||||
if (!inline_macro) {
|
||||
if (converted.IsOnStack()) {
|
||||
argument_range->Extend(converted.stack_range());
|
||||
} else {
|
||||
@ -2444,18 +2450,33 @@ VisitResult ImplementationVisitor::GenerateCall(
|
||||
}
|
||||
}
|
||||
|
||||
bool inline_macro = callable->ShouldBeInlined();
|
||||
std::vector<VisitResult> implicit_arguments;
|
||||
for (size_t i = 0; i < callable->signature().implicit_count; ++i) {
|
||||
std::string implicit_name = callable->signature().parameter_names[i]->value;
|
||||
base::Optional<Binding<LocalValue>*> val =
|
||||
TryLookupLocalValue(implicit_name);
|
||||
if (!val) {
|
||||
ReportError("implicit parameter '", implicit_name,
|
||||
"' required for call to '", callable->ReadableName(),
|
||||
"' is not defined");
|
||||
if (val) {
|
||||
implicit_arguments.push_back(
|
||||
GenerateFetchFromLocation((*val)->GetLocationReference(*val)));
|
||||
} else {
|
||||
VisitResult unititialized = VisitResult::TopTypeResult(
|
||||
"implicit parameter '" + implicit_name +
|
||||
"' is not defined when invoking " + callable->ReadableName() +
|
||||
" at " + PositionAsString(CurrentSourcePosition::Get()),
|
||||
callable->signature().parameter_types.types[i]);
|
||||
implicit_arguments.push_back(unititialized);
|
||||
}
|
||||
const Type* type = implicit_arguments.back().type();
|
||||
if (const TopType* top_type = TopType::DynamicCast(type)) {
|
||||
if (!callable->IsMacro() || callable->IsExternal()) {
|
||||
ReportError(
|
||||
"unititialized implicit parameters can only be passed to "
|
||||
"Torque-defined macros: the ",
|
||||
top_type->reason());
|
||||
}
|
||||
inline_macro = true;
|
||||
}
|
||||
implicit_arguments.push_back(
|
||||
GenerateFetchFromLocation((*val)->GetLocationReference(*val)));
|
||||
}
|
||||
|
||||
std::vector<VisitResult> converted_arguments;
|
||||
@ -2467,7 +2488,7 @@ VisitResult ImplementationVisitor::GenerateCall(
|
||||
AddCallParameter(callable, implicit_arguments[current],
|
||||
callable->signature().parameter_types.types[current],
|
||||
&converted_arguments, &argument_range,
|
||||
&constexpr_arguments);
|
||||
&constexpr_arguments, inline_macro);
|
||||
}
|
||||
|
||||
if (this_reference) {
|
||||
@ -2476,7 +2497,7 @@ VisitResult ImplementationVisitor::GenerateCall(
|
||||
// By now, the this reference should either be a variable, a temporary or
|
||||
// a Slice. In either case the fetch of the VisitResult should succeed.
|
||||
VisitResult this_value = this_reference->GetVisitResult();
|
||||
if (method->ShouldBeInlined()) {
|
||||
if (inline_macro) {
|
||||
if (!this_value.type()->IsSubtypeOf(method->aggregate_type())) {
|
||||
ReportError("this parameter must be a subtype of ",
|
||||
*method->aggregate_type(), " but it is of type ",
|
||||
@ -2485,7 +2506,7 @@ VisitResult ImplementationVisitor::GenerateCall(
|
||||
} else {
|
||||
AddCallParameter(callable, this_value, method->aggregate_type(),
|
||||
&converted_arguments, &argument_range,
|
||||
&constexpr_arguments);
|
||||
&constexpr_arguments, inline_macro);
|
||||
}
|
||||
++current;
|
||||
}
|
||||
@ -2495,7 +2516,7 @@ VisitResult ImplementationVisitor::GenerateCall(
|
||||
? TypeOracle::GetObjectType()
|
||||
: callable->signature().types()[current++];
|
||||
AddCallParameter(callable, arg, to_type, &converted_arguments,
|
||||
&argument_range, &constexpr_arguments);
|
||||
&argument_range, &constexpr_arguments, inline_macro);
|
||||
}
|
||||
|
||||
size_t label_count = callable->signature().labels.size();
|
||||
@ -2559,7 +2580,7 @@ VisitResult ImplementationVisitor::GenerateCall(
|
||||
}
|
||||
result << "))";
|
||||
return VisitResult(return_type, result.str());
|
||||
} else if (macro->ShouldBeInlined()) {
|
||||
} else if (inline_macro) {
|
||||
std::vector<Block*> label_blocks;
|
||||
for (Binding<LocalLabel>* label : arguments.labels) {
|
||||
label_blocks.push_back(label->block);
|
||||
@ -2874,8 +2895,13 @@ VisitResult ImplementationVisitor::GenerateImplicitConvert(
|
||||
return scope.Yield(GenerateCopy(source));
|
||||
} else {
|
||||
std::stringstream s;
|
||||
s << "cannot use expression of type " << *source.type()
|
||||
<< " as a value of type " << *destination_type;
|
||||
if (const TopType* top_type = TopType::DynamicCast(source.type())) {
|
||||
s << "undefined expression of type " << *destination_type << ": the "
|
||||
<< top_type->reason();
|
||||
} else {
|
||||
s << "cannot use expression of type " << *source.type()
|
||||
<< " as a value of type " << *destination_type;
|
||||
}
|
||||
ReportError(s.str());
|
||||
}
|
||||
}
|
||||
|
@ -693,7 +693,8 @@ class ImplementationVisitor {
|
||||
const Type* parameter_type,
|
||||
std::vector<VisitResult>* converted_arguments,
|
||||
StackRange* argument_range,
|
||||
std::vector<std::string>* constexpr_arguments);
|
||||
std::vector<std::string>* constexpr_arguments,
|
||||
bool inline_macro);
|
||||
|
||||
VisitResult GenerateCall(Callable* callable,
|
||||
base::Optional<LocationReference> this_parameter,
|
||||
|
@ -912,6 +912,13 @@ VisitResult VisitResult::NeverResult() {
|
||||
return result;
|
||||
}
|
||||
|
||||
VisitResult VisitResult::TopTypeResult(std::string top_reason,
|
||||
const Type* from_type) {
|
||||
VisitResult result;
|
||||
result.type_ = TypeOracle::GetTopType(std::move(top_reason), from_type);
|
||||
return result;
|
||||
}
|
||||
|
||||
std::tuple<size_t, std::string> Field::GetFieldSizeInformation() const {
|
||||
auto optional = SizeOf(this->name_and_type.type);
|
||||
if (optional.has_value()) {
|
||||
|
@ -756,6 +756,8 @@ class VisitResult {
|
||||
DCHECK(type->IsConstexpr());
|
||||
}
|
||||
static VisitResult NeverResult();
|
||||
static VisitResult TopTypeResult(std::string top_reason,
|
||||
const Type* from_type);
|
||||
VisitResult(const Type* type, StackRange stack_range)
|
||||
: type_(type), stack_range_(stack_range) {
|
||||
DCHECK(!type->IsConstexpr());
|
||||
|
@ -849,6 +849,55 @@ TEST(Torque, FieldAccessOnNonClassType) {
|
||||
HasSubstr("map"));
|
||||
}
|
||||
|
||||
TEST(Torque, UnusedImplicit) {
|
||||
ExpectSuccessfulCompilation(R"(
|
||||
@export
|
||||
macro Test1(implicit c: Smi)(a: Object): Object { return a; }
|
||||
@export
|
||||
macro Test2(b: Object) { Test1(b); }
|
||||
)");
|
||||
|
||||
ExpectFailingCompilation(
|
||||
R"(
|
||||
macro Test1(implicit c: Smi)(_a: Object): Smi { return c; }
|
||||
@export
|
||||
macro Test2(b: Smi) { Test1(b); }
|
||||
)",
|
||||
HasSubstr("undefined expression of type Smi: the implicit "
|
||||
"parameter 'c' is not defined when invoking Test1 at"));
|
||||
|
||||
ExpectFailingCompilation(
|
||||
R"(
|
||||
extern macro Test3(implicit c: Smi)(Object): Smi;
|
||||
@export
|
||||
macro Test4(b: Smi) { Test3(b); }
|
||||
)",
|
||||
HasSubstr("unititialized implicit parameters can only be passed to "
|
||||
"Torque-defined macros: the implicit parameter 'c' is not "
|
||||
"defined when invoking Test3"));
|
||||
ExpectSuccessfulCompilation(
|
||||
R"(
|
||||
macro Test7<T: type>(implicit c: Smi)(o: T): Smi;
|
||||
Test7<Smi>(implicit c: Smi)(o: Smi): Smi { return o; }
|
||||
@export
|
||||
macro Test8(b: Smi) { Test7(b); }
|
||||
)");
|
||||
|
||||
ExpectFailingCompilation(
|
||||
R"(
|
||||
macro Test6<T: type>(_o: T): T;
|
||||
macro Test6<T: type>(implicit c: T)(_o: T): T {
|
||||
return c;
|
||||
}
|
||||
macro Test7<T: type>(o: T): Smi;
|
||||
Test7<Smi>(o: Smi): Smi { return Test6<Smi>(o); }
|
||||
@export
|
||||
macro Test8(b: Smi) { Test7(b); }
|
||||
)",
|
||||
HasSubstr("\nambiguous callable : \n Test6(Smi)\ncandidates are:\n "
|
||||
"Test6(Smi): Smi\n Test6(implicit Smi)(Smi): Smi"));
|
||||
}
|
||||
|
||||
} // namespace torque
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
Loading…
Reference in New Issue
Block a user