Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 8 additions & 9 deletions Analysis/src/Error.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -496,23 +496,20 @@ struct ErrorConverter

std::string operator()(const Luau::MissingProperties& e) const
{
std::string s = "Table type '" + toString(e.subType) + "' not compatible with type '" + toString(e.superType) + "' because the former";

std::string s;
std::string afterFieldList;
std::string pluralSuffix = e.properties.size() > 1 ? "s " : " ";
switch (e.context)
{
case MissingProperties::Missing:
s += " is missing field";
s += "required field" + pluralSuffix;
afterFieldList = " not";
break;
case MissingProperties::Extra:
s += " has extra field";
s += "extra field" + pluralSuffix;
break;
}

if (e.properties.size() > 1)
s += "s";

s += " ";

for (size_t i = 0; i < e.properties.size(); ++i)
{
if (i > 0)
Expand All @@ -524,6 +521,8 @@ struct ErrorConverter
s += "'" + e.properties[i] + "'";
}

s += afterFieldList + " found in type '" + toString(e.subType) + "' from expected type '" + toString(e.superType) + "'";

return s;
}

Expand Down
9 changes: 2 additions & 7 deletions tests/Frontend.test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -938,15 +938,10 @@ TEST_CASE_FIXTURE(FrontendFixture, "it_should_be_safe_to_stringify_errors_when_f
// It could segfault, or you could see weird type names like the empty string or <VALUELESS BY EXCEPTION>
if (!FFlag::DebugLuauForceOldSolver)
{
CHECK_EQ(
"Table type '{ count: string }' not compatible with type '{ Count: number }' because the former is missing field 'Count'",
toString(result.errors[0])
);
CHECK_EQ("required field 'Count' not found in type '{ count: string }' from expected type '{ Count: number }'", toString(result.errors[0]));
}
else
REQUIRE_EQ(
"Table type 'a' not compatible with type '{ Count: number }' because the former is missing field 'Count'", toString(result.errors[0])
);
REQUIRE_EQ("required field 'Count' not found in type 'a' from expected type '{ Count: number }'", toString(result.errors[0]));
}

TEST_CASE_FIXTURE(FrontendFixture, "trace_requires_in_nonstrict_mode")
Expand Down
2 changes: 1 addition & 1 deletion tests/TypeInfer.functions.test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2303,7 +2303,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "param_1_and_2_both_takes_the_same_generic_bu
const std::string expected = R"(Expected this to be 'vec2?', but got '{| x: number |}'
caused by:
None of the union options are compatible. For example:
Table type '{| x: number |}' not compatible with type 'vec2' because the former is missing field 'y')";
required field 'y' not found in type '{| x: number |}' from expected type 'vec2')";
CHECK_EQ(expected, toString(result.errors[0]));
CHECK_EQ("Expected this to be 'number', but got 'vec2'", toString(result.errors[1]));
}
Expand Down
16 changes: 6 additions & 10 deletions tests/TypeInfer.singletons.test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -391,8 +391,7 @@ TEST_CASE_FIXTURE(Fixture, "table_properties_type_error_escapes")

LUAU_REQUIRE_ERROR_COUNT(1, result);

const std::string expected =
R"(Table type '{ ["\n"]: number }' not compatible with type '{ ["<>"]: number }' because the former is missing field '<>')";
const std::string expected = R"(required field '<>' not found in type '{ ["\n"]: number }' from expected type '{ ["<>"]: number }')";
CHECK(expected == toString(result.errors[0]));
}

Expand All @@ -409,15 +408,14 @@ local a: Animal = { tag = 'cat', cafood = 'something' }
LUAU_REQUIRE_ERROR_COUNT(1, result);
if (!FFlag::DebugLuauForceOldSolver)
CHECK(
R"(Table type '{ cafood: string, tag: "cat" }' not compatible with type 'Cat' because the former is missing field 'catfood')" ==
toString(result.errors[0])
R"(required field 'catfood' not found in type '{ cafood: string, tag: "cat" }' from expected type 'Cat')" == toString(result.errors[0])
);
else
{
const std::string expected = R"(Expected this to be 'Cat | Dog', but got 'a'
caused by:
None of the union options are compatible. For example:
Table type 'a' not compatible with type 'Cat' because the former is missing field 'catfood')";
required field 'catfood' not found in type 'a' from expected type 'Cat')";
CHECK_EQ(expected, toString(result.errors[0]));
}
}
Expand All @@ -436,16 +434,15 @@ local a: Result = { success = false, result = 'something' }
if (!FFlag::DebugLuauForceOldSolver)
{
CHECK_EQ(
"Table type '{ result: string, success: false }' not compatible with type 'Bad' because the former is missing field 'error'",
toString(result.errors[0])
"required field 'error' not found in type '{ result: string, success: false }' from expected type 'Bad'", toString(result.errors[0])
);
}
else
{
const std::string expected = R"(Expected this to be 'Bad | Good', but got 'a'
caused by:
None of the union options are compatible. For example:
Table type 'a' not compatible with type 'Bad' because the former is missing field 'error')";
required field 'error' not found in type 'a' from expected type 'Bad')";
CHECK_EQ(expected, toString(result.errors[0]));
}
}
Expand All @@ -466,8 +463,7 @@ TEST_CASE_FIXTURE(Fixture, "parametric_tagged_union_alias")
LUAU_REQUIRE_ERROR_COUNT(1, result);

CHECK_EQ(
"Table type '{ result: string, success: false }' not compatible with type 'Err<number>' because the former is missing field 'error'",
toString(result.errors[0])
"required field 'error' not found in type '{ result: string, success: false }' from expected type 'Err<number>'", toString(result.errors[0])
);
}

Expand Down
13 changes: 6 additions & 7 deletions tests/TypeInfer.tables.test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2625,7 +2625,7 @@ local y: number = tmp.p.y
const std::string expected = R"(Expected this to be exactly 'HasSuper', but got 'tmp'
caused by:
Property 'p' is not compatible.
Table type '{| x: number, y: number |}' not compatible with type 'Super' because the former has extra field 'y')";
extra field 'y' found in type '{| x: number, y: number |}' from expected type 'Super')";
CHECK_EQ(expected, toString(result.errors[0]));
}
}
Expand Down Expand Up @@ -3711,14 +3711,14 @@ TEST_CASE_FIXTURE(Fixture, "scalar_is_not_a_subtype_of_a_compatible_polymorphic_
R"(Expected this to be 't1 where t1 = {- absolutely_no_scalar_has_this_method: (t1) -> (a...) -}', but got 'string'
caused by:
The given type's metatable does not satisfy the requirements.
Table type 'typeof(string)' not compatible with type 't1 where t1 = {- absolutely_no_scalar_has_this_method: (t1) -> (a...) -}' because the former is missing field 'absolutely_no_scalar_has_this_method')";
required field 'absolutely_no_scalar_has_this_method' not found in type 'typeof(string)' from expected type 't1 where t1 = {- absolutely_no_scalar_has_this_method: (t1) -> (a...) -}')";
CHECK_EQ(expected1, toString(result.errors[0]));

const std::string expected2 =
R"(Expected this to be 't1 where t1 = {- absolutely_no_scalar_has_this_method: (t1) -> (a...) -}', but got '"bar"'
caused by:
The given type's metatable does not satisfy the requirements.
Table type 'typeof(string)' not compatible with type 't1 where t1 = {- absolutely_no_scalar_has_this_method: (t1) -> (a...) -}' because the former is missing field 'absolutely_no_scalar_has_this_method')";
required field 'absolutely_no_scalar_has_this_method' not found in type 'typeof(string)' from expected type 't1 where t1 = {- absolutely_no_scalar_has_this_method: (t1) -> (a...) -}')";
CHECK_EQ(expected2, toString(result.errors[1]));

const std::string expected3 = R"(Expected this to be
Expand All @@ -3730,7 +3730,7 @@ caused by:
Expected this to be 't1 where t1 = {- absolutely_no_scalar_has_this_method: (t1) -> (a...) -}', but got '"bar"'
caused by:
The given type's metatable does not satisfy the requirements.
Table type 'typeof(string)' not compatible with type 't1 where t1 = {- absolutely_no_scalar_has_this_method: (t1) -> (a...) -}' because the former is missing field 'absolutely_no_scalar_has_this_method')";
required field 'absolutely_no_scalar_has_this_method' not found in type 'typeof(string)' from expected type 't1 where t1 = {- absolutely_no_scalar_has_this_method: (t1) -> (a...) -}')";
CHECK_EQ(expected3, toString(result.errors[2]));
}
}
Expand Down Expand Up @@ -3780,7 +3780,7 @@ TEST_CASE_FIXTURE(Fixture, "a_free_shape_cannot_turn_into_a_scalar_if_it_is_not_
R"(Expected this to be 'string', but got 't1 where t1 = {+ absolutely_no_scalar_has_this_method: (t1) -> (a, b...) +}'
caused by:
The given type's metatable does not satisfy the requirements.
Table type 'typeof(string)' not compatible with type 't1 where t1 = {+ absolutely_no_scalar_has_this_method: (t1) -> (a, b...) +}' because the former is missing field 'absolutely_no_scalar_has_this_method')";
required field 'absolutely_no_scalar_has_this_method' not found in type 'typeof(string)' from expected type 't1 where t1 = {+ absolutely_no_scalar_has_this_method: (t1) -> (a, b...) +}')";
CHECK_EQ(expected, toString(result.errors[0]));

CHECK_EQ("<a, b...>(t1) -> string where t1 = {+ absolutely_no_scalar_has_this_method: (t1) -> (a, b...) +}", toString(requireType("f")));
Expand Down Expand Up @@ -5708,8 +5708,7 @@ TEST_CASE_FIXTURE(Fixture, "bigger_nested_table_causes_big_type_error")
)");

LUAU_REQUIRE_ERROR_COUNT(1, result);
std::string expected =
R"(Table type '{ path: string, type: "file" }' not compatible with type 'File' because the former is missing field 'name')";
std::string expected = R"(required field 'name' not found in type '{ path: string, type: "file" }' from expected type 'File')";
CHECK_EQ(expected, toString(result.errors[0]));
CHECK_EQ(result.errors[0].location, Location{{21, 20}, {24, 21}});
}
Expand Down
2 changes: 1 addition & 1 deletion tests/TypeInfer.test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1195,7 +1195,7 @@ TEST_CASE_FIXTURE(Fixture, "cli_50041_committing_txnlog_in_apollo_client_error")
"'FieldSpecifier'"
"\ncaused by:\n"
" Not all intersection parts are compatible.\n"
"Table type 'FieldSpecifier' not compatible with type '{ from: number? }' because the former has extra field 'fieldName'";
"extra field 'fieldName' found in type 'FieldSpecifier' from expected type '{ from: number? }'";
CHECK_EQ(expected, toString(result.errors[0]));
}
else
Expand Down
8 changes: 4 additions & 4 deletions tests/TypeInfer.unionTypes.test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -547,7 +547,7 @@ end
CHECK_EQ(toString(result.errors[0]), R"(Expected this to be '{ w: number }', but got 'X | Y | Z'
caused by:
Not all union options are compatible.
Table type 'X' not compatible with type '{ w: number }' because the former is missing field 'w')");
required field 'w' not found in type 'X' from expected type '{ w: number }')");
}
}

Expand Down Expand Up @@ -582,13 +582,13 @@ local a: X? = { w = 4 }

LUAU_REQUIRE_ERROR_COUNT(1, result);
if (!FFlag::DebugLuauForceOldSolver)
CHECK("Table type '{ w: number }' not compatible with type 'X' because the former is missing field 'x'" == toString(result.errors[0]));
CHECK("required field 'x' not found in type '{ w: number }' from expected type 'X'" == toString(result.errors[0]));
else
{
const std::string expected = R"(Expected this to be 'X?', but got 'a'
caused by:
None of the union options are compatible. For example:
Table type 'a' not compatible with type 'X' because the former is missing field 'x')";
required field 'x' not found in type 'a' from expected type 'X')";
CHECK_EQ(expected, toString(result.errors[0]));
}
}
Expand Down Expand Up @@ -1116,7 +1116,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "oss_2025")

local baz: a? = bar.test

table.insert(foo, bar)
table.insert(foo, bar)
)"));
}

Expand Down
Loading