e620ba139b
For every @noVerifier in base.tq, this change either removes it or ensures that it has some annotation explaining why it can't be removed. The @noVerifier usages that can't be removed fall into the following categories: 1. Classes that don't have their own instance types and therefore have no meaningful way to do an Is...() check 2. Fields that might not exist 3. Fields that are waiting for MaybeObject support in Torque Bug: v8:9311 Change-Id: Id452d4151ec07347ae96a9b5f3b26e2ac8065d31 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1659134 Reviewed-by: Daniel Clifford <danno@chromium.org> Reviewed-by: Tobias Tebbi <tebbi@chromium.org> Commit-Queue: Seth Brenith <seth.brenith@microsoft.com> Cr-Commit-Position: refs/heads/master@{#62263}
317 lines
8.3 KiB
C++
317 lines
8.3 KiB
C++
// Copyright 2018 the V8 project authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
#include "src/torque/torque-compiler.h"
|
|
#include "src/torque/utils.h"
|
|
#include "test/unittests/test-utils.h"
|
|
#include "testing/gmock-support.h"
|
|
|
|
namespace v8 {
|
|
namespace internal {
|
|
namespace torque {
|
|
|
|
namespace {
|
|
|
|
// This is a simplified version of the basic Torque type definitions.
|
|
// Some class types are replaced by abstact types to keep it self-contained and
|
|
// small.
|
|
constexpr const char* kTestTorquePrelude = R"(
|
|
type void;
|
|
type never;
|
|
|
|
type Tagged generates 'TNode<Object>' constexpr 'ObjectPtr';
|
|
type Smi extends Tagged generates 'TNode<Smi>' constexpr 'Smi';
|
|
|
|
@abstract
|
|
extern class HeapObject extends Tagged {
|
|
map: Map;
|
|
}
|
|
type Map extends HeapObject generates 'TNode<Map>';
|
|
type Object = Smi | HeapObject;
|
|
type JSReceiver extends HeapObject generates 'TNode<JSReceiver>';
|
|
type JSObject extends JSReceiver generates 'TNode<JSObject>';
|
|
type int32 generates 'TNode<Int32T>' constexpr 'int32_t';
|
|
type uint32 generates 'TNode<Uint32T>' constexpr 'uint32_t';
|
|
type int31 extends int32
|
|
generates 'TNode<Int32T>' constexpr 'int31_t';
|
|
type uint31 extends uint32
|
|
generates 'TNode<Uint32T>' constexpr 'uint31_t';
|
|
type int16 extends int31
|
|
generates 'TNode<Int16T>' constexpr 'int16_t';
|
|
type uint16 extends uint31
|
|
generates 'TNode<Uint16T>' constexpr 'uint16_t';
|
|
type int8 extends int16 generates 'TNode<Int8T>' constexpr 'int8_t';
|
|
type uint8 extends uint16
|
|
generates 'TNode<Uint8T>' constexpr 'uint8_t';
|
|
type int64 generates 'TNode<Int64T>' constexpr 'int64_t';
|
|
type intptr generates 'TNode<IntPtrT>' constexpr 'intptr_t';
|
|
type uintptr generates 'TNode<UintPtrT>' constexpr 'uintptr_t';
|
|
type float32 generates 'TNode<Float32T>' constexpr 'float';
|
|
type float64 generates 'TNode<Float64T>' constexpr 'double';
|
|
type bool generates 'TNode<BoolT>' constexpr 'bool';
|
|
type bint generates 'TNode<BInt>' constexpr 'BInt';
|
|
type string constexpr 'const char*';
|
|
type RawPtr generates 'TNode<RawPtrT>' constexpr 'void*';
|
|
type Code extends HeapObject generates 'TNode<Code>';
|
|
type BuiltinPtr extends Smi generates 'TNode<BuiltinPtr>';
|
|
type Context extends HeapObject generates 'TNode<Context>';
|
|
type NativeContext extends Context;
|
|
)";
|
|
|
|
TorqueCompilerResult TestCompileTorque(std::string source) {
|
|
TorqueCompilerOptions options;
|
|
options.output_directory = "";
|
|
options.collect_language_server_data = false;
|
|
options.force_assert_statements = false;
|
|
options.v8_root = ".";
|
|
|
|
source = kTestTorquePrelude + source;
|
|
return CompileTorque(source, options);
|
|
}
|
|
|
|
void ExpectSuccessfulCompilation(std::string source) {
|
|
TorqueCompilerResult result = TestCompileTorque(std::move(source));
|
|
std::vector<std::string> messages;
|
|
for (const auto& message : result.messages) {
|
|
messages.push_back(message.message);
|
|
}
|
|
EXPECT_EQ(messages, std::vector<std::string>{});
|
|
}
|
|
|
|
template <class T>
|
|
void ExpectFailingCompilation(
|
|
std::string source, ::testing::PolymorphicMatcher<T> message_pattern) {
|
|
TorqueCompilerResult result = TestCompileTorque(std::move(source));
|
|
ASSERT_FALSE(result.messages.empty());
|
|
EXPECT_THAT(result.messages[0].message, message_pattern);
|
|
}
|
|
|
|
} // namespace
|
|
|
|
TEST(Torque, Prelude) { ExpectSuccessfulCompilation(""); }
|
|
|
|
TEST(Torque, StackDeleteRange) {
|
|
Stack<int> stack = {1, 2, 3, 4, 5, 6, 7};
|
|
stack.DeleteRange(StackRange{BottomOffset{2}, BottomOffset{4}});
|
|
Stack<int> result = {1, 2, 5, 6, 7};
|
|
ASSERT_TRUE(stack == result);
|
|
}
|
|
|
|
using ::testing::HasSubstr;
|
|
TEST(Torque, TypeNamingConventionLintError) {
|
|
ExpectFailingCompilation(R"(
|
|
type foo generates 'TNode<Foo>';
|
|
)",
|
|
HasSubstr("\"foo\""));
|
|
}
|
|
|
|
TEST(Torque, StructNamingConventionLintError) {
|
|
ExpectFailingCompilation(R"(
|
|
struct foo {}
|
|
)",
|
|
HasSubstr("\"foo\""));
|
|
}
|
|
|
|
TEST(Torque, ClassDefinition) {
|
|
ExpectSuccessfulCompilation(R"(
|
|
extern class TestClassWithAllTypes extends HeapObject {
|
|
a: int8;
|
|
b: uint8;
|
|
b2: uint8;
|
|
b3: uint8;
|
|
c: int16;
|
|
d: uint16;
|
|
e: int32;
|
|
f: uint32;
|
|
g: RawPtr;
|
|
h: intptr;
|
|
i: uintptr;
|
|
}
|
|
|
|
@export
|
|
macro TestClassWithAllTypesLoadsAndStores(
|
|
t: TestClassWithAllTypes, r: RawPtr, v1: int8, v2: uint8, v3: int16,
|
|
v4: uint16, v5: int32, v6: uint32, v7: intptr, v8: uintptr) {
|
|
t.a = v1;
|
|
t.b = v2;
|
|
t.c = v3;
|
|
t.d = v4;
|
|
t.e = v5;
|
|
t.f = v6;
|
|
t.g = r;
|
|
t.h = v7;
|
|
t.i = v8;
|
|
t.a = t.a;
|
|
t.b = t.b;
|
|
t.c = t.c;
|
|
t.d = t.d;
|
|
t.e = t.e;
|
|
t.f = t.f;
|
|
t.g = t.g;
|
|
t.h = t.h;
|
|
t.i = t.i;
|
|
}
|
|
)");
|
|
}
|
|
|
|
TEST(Torque, TypeDeclarationOrder) {
|
|
ExpectSuccessfulCompilation(R"(
|
|
type Baztype = Foo | FooType;
|
|
|
|
@abstract
|
|
extern class Foo extends HeapObject {
|
|
fooField: FooType;
|
|
}
|
|
|
|
extern class Bar extends Foo {
|
|
barField: Bartype;
|
|
bazfield: Baztype;
|
|
}
|
|
|
|
type Bartype = FooType;
|
|
|
|
type FooType = Smi | Bar;
|
|
)");
|
|
}
|
|
|
|
TEST(Torque, ConditionalFields) {
|
|
// This class should throw alignment errors if @if decorators aren't
|
|
// working.
|
|
ExpectSuccessfulCompilation(R"(
|
|
extern class PreprocessingTest extends HeapObject {
|
|
@if(FALSE_FOR_TESTING) a: int8;
|
|
@if(TRUE_FOR_TESTING) a: int16;
|
|
b: int16;
|
|
d: int32;
|
|
@ifnot(TRUE_FOR_TESTING) e: int8;
|
|
@ifnot(FALSE_FOR_TESTING) f: int16;
|
|
g: int16;
|
|
h: int32;
|
|
}
|
|
)");
|
|
ExpectFailingCompilation(R"(
|
|
extern class PreprocessingTest extends HeapObject {
|
|
@if(TRUE_FOR_TESTING) a: int8;
|
|
@if(FALSE_FOR_TESTING) a: int16;
|
|
b: int16;
|
|
d: int32;
|
|
@ifnot(FALSE_FOR_TESTING) e: int8;
|
|
@ifnot(TRUE_FOR_TESTING) f: int16;
|
|
g: int16;
|
|
h: int32;
|
|
}
|
|
)",
|
|
HasSubstr("aligned"));
|
|
}
|
|
|
|
TEST(Torque, ConstexprLetBindingDoesNotCrash) {
|
|
ExpectFailingCompilation(
|
|
R"(@export macro FooBar() { let foo = 0; check(foo >= 0); })",
|
|
HasSubstr("Use 'const' instead of 'let' for variable 'foo'"));
|
|
}
|
|
|
|
TEST(Torque, DoubleUnderScorePrefixIllegalForIdentifiers) {
|
|
ExpectFailingCompilation(R"(
|
|
@export macro Foo() {
|
|
let __x;
|
|
}
|
|
)",
|
|
HasSubstr("Lexer Error"));
|
|
}
|
|
|
|
TEST(Torque, UnusedLetBindingLintError) {
|
|
ExpectFailingCompilation(R"(
|
|
@export macro Foo(y: Smi) {
|
|
let x: Smi = y;
|
|
}
|
|
)",
|
|
HasSubstr("Variable 'x' is never used."));
|
|
}
|
|
|
|
TEST(Torque, UnderscorePrefixSilencesUnusedWarning) {
|
|
ExpectSuccessfulCompilation(R"(
|
|
@export macro Foo(y: Smi) {
|
|
let _x: Smi = y;
|
|
}
|
|
)");
|
|
}
|
|
|
|
TEST(Torque, UsingUnderscorePrefixedIdentifierError) {
|
|
ExpectFailingCompilation(R"(
|
|
@export macro Foo(y: Smi) {
|
|
let _x: Smi = y;
|
|
check(_x == y);
|
|
}
|
|
)",
|
|
HasSubstr("Trying to reference '_x'"));
|
|
}
|
|
|
|
TEST(Torque, UnusedArgumentLintError) {
|
|
ExpectFailingCompilation(R"(
|
|
@export macro Foo(x: Smi) {}
|
|
)",
|
|
HasSubstr("Variable 'x' is never used."));
|
|
}
|
|
|
|
TEST(Torque, UsingUnderscorePrefixedArgumentSilencesWarning) {
|
|
ExpectSuccessfulCompilation(R"(
|
|
@export macro Foo(_y: Smi) {}
|
|
)");
|
|
}
|
|
|
|
TEST(Torque, UnusedLabelLintError) {
|
|
ExpectFailingCompilation(R"(
|
|
@export macro Foo() labels Bar {}
|
|
)",
|
|
HasSubstr("Label 'Bar' is never used."));
|
|
}
|
|
|
|
TEST(Torque, UsingUnderScorePrefixLabelSilencesWarning) {
|
|
ExpectSuccessfulCompilation(R"(
|
|
@export macro Foo() labels _Bar {}
|
|
)");
|
|
}
|
|
|
|
TEST(Torque, NoUnusedWarningForImplicitArguments) {
|
|
ExpectSuccessfulCompilation(R"(
|
|
@export macro Foo(implicit c: Context, r: JSReceiver)() {}
|
|
)");
|
|
}
|
|
|
|
TEST(Torque, NoUnusedWarningForVariablesOnlyUsedInAsserts) {
|
|
ExpectSuccessfulCompilation(R"(
|
|
@export macro Foo(x: bool) {
|
|
assert(x);
|
|
}
|
|
)");
|
|
}
|
|
|
|
TEST(Torque, ImportNonExistentFile) {
|
|
ExpectFailingCompilation(R"(import "foo/bar.tq")",
|
|
HasSubstr("File 'foo/bar.tq' not found."));
|
|
}
|
|
|
|
TEST(Torque, LetShouldBeConstLintError) {
|
|
ExpectFailingCompilation(R"(
|
|
@export macro Foo(y: Smi): Smi {
|
|
let x: Smi = y;
|
|
return x;
|
|
})",
|
|
HasSubstr("Variable 'x' is never assigned to."));
|
|
}
|
|
|
|
TEST(Torque, LetShouldBeConstIsSkippedForStructs) {
|
|
ExpectSuccessfulCompilation(R"(
|
|
struct Foo{ a: Smi; }
|
|
@export macro Bar(x: Smi): Foo {
|
|
let foo = Foo{a: x};
|
|
return foo;
|
|
}
|
|
)");
|
|
}
|
|
|
|
} // namespace torque
|
|
} // namespace internal
|
|
} // namespace v8
|