chmod a-w a property of the discriminant type

This commit is contained in:
Alexander McCord 2025-03-24 13:54:53 -07:00
parent 5f42e63a73
commit 4a1d820864
2 changed files with 42 additions and 7 deletions

View file

@ -45,6 +45,7 @@ LUAU_FASTFLAGVARIABLE(LuauInferLocalTypesInMultipleAssignments)
LUAU_FASTFLAGVARIABLE(LuauDoNotLeakNilInRefinement)
LUAU_FASTFLAGVARIABLE(LuauExtraFollows)
LUAU_FASTFLAG(LuauUserTypeFunTypecheck)
LUAU_FASTFLAGVARIABLE(LuauRefineJustTheReadProperty)
namespace Luau
{
@ -529,11 +530,18 @@ void ConstraintGenerator::computeRefinement(
TypeId nextDiscriminantTy = arena->addType(TableType{});
NotNull<TableType> table{getMutable<TableType>(nextDiscriminantTy)};
// When we fully support read-write properties (i.e. when we allow properties with
// completely disparate read and write types), then the following property can be
// set to read-only since refinements only tell us about what we read. This cannot
// be allowed yet though because it causes read and write types to diverge.
table->props[*key->propName] = Property::rw(discriminantTy);
if (FFlag::LuauRefineJustTheReadProperty)
{
table->props[*key->propName] = Property::readonly(discriminantTy);
}
else
{
// When we fully support read-write properties (i.e. when we allow properties with
// completely disparate read and write types), then the following property can be
// set to read-only since refinements only tell us about what we read. This cannot
// be allowed yet though because it causes read and write types to diverge.
table->props[*key->propName] = Property::rw(discriminantTy);
}
table->scope = scope.get();
table->state = TableState::Sealed;
@ -547,7 +555,7 @@ void ConstraintGenerator::computeRefinement(
refis->get(proposition->key->def)->shouldAppendNilType =
(sense || !eq) && containsSubscriptedDefinition(proposition->key->def) && !proposition->implicitFromCall;
}
else
else
{
refis->get(proposition->key->def)->shouldAppendNilType = (sense || !eq) && containsSubscriptedDefinition(proposition->key->def);
}

View file

@ -14,6 +14,7 @@ LUAU_FASTFLAG(LuauIntersectNotNil)
LUAU_FASTFLAG(LuauSkipNoRefineDuringRefinement)
LUAU_FASTFLAG(LuauFunctionCallsAreNotNilable)
LUAU_FASTFLAG(LuauDoNotLeakNilInRefinement)
LUAU_FASTFLAG(LuauRefineJustTheReadProperty)
using namespace Luau;
@ -2538,7 +2539,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "function_calls_are_not_nillable")
return nil
end
)"));
}
TEST_CASE_FIXTURE(BuiltinsFixture, "oss_1528_method_calls_are_not_nillable")
@ -2562,4 +2562,31 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "oss_1528_method_calls_are_not_nillable")
)"));
}
TEST_CASE_FIXTURE(Fixture, "refine_just_the_read_property")
{
ScopedFastFlag sff[]{
{FFlag::LuauSolverV2, true},
{FFlag::LuauRefineJustTheReadProperty, true},
};
CheckResult result = check(R"(
type Foo = { p: boolean }
function f(x: Foo)
if x.p == true then return end
x.p = true
x.p = false
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
// The first check is corrrect because it reflects the state of the program by that point.
// The second check is not. It fails to account for transitive typestate change from the
// previous statement.
CHECK_EQ("Foo & { read p: ~true }", toString(requireTypeAtPosition({6, 12})));
CHECK_EQ("Foo & { read p: ~true }", toString(requireTypeAtPosition({7, 12})));
}
TEST_SUITE_END();