When using the new type solver in --!nonstrict mode, if any kind of variable is specifically defined as any instance, it will incorrectly label any indexing of that instance as a type error even if the index is present as a child of the instance at the time of type checking, with the message “Key ‘Part’ not found in external type ‘Model’” (Or whatever other kind of types you’re using)
Previously, this did not happen in nonstrict mode, and there is no discernable benefit to this behavior, so I can only assume that this is a bug.
Reproducing is very simple, just put a Model as a child of a Script, and put a Part into the Model, and then type this:
--!nonstrict
local Mdl : Model = script.TestModel
local Prt : Part = Mdl.Part
-- Type Error: Key 'Part' not found in external type 'Model'
local Mdl2 = script.TestModel
local Prt2 = Mdl.Part
-- No type error, though autocomplete does still show correctly that "Mdl2" is of type Model.
Another example of how this can be strange is in a case like this:
local Character = Plr.Character
print(Character.HumanoidRootPart)
-- If you tried to do "Plr.Character.HumanoidRootPart", or if you defined "Character" as a Model, that would be a type error.
Expected behavior
This behavior might be part of the --!strict type checking mode and may have accidentally been enabled in nonstrict mode, though I’m unsure of that and either way I would expect that indexing an instance in this fashion to not produce a type error as it is generally not useful.
If I am reading your code correctly, and understanding how you’ve laid out the data model, this is intended behavior for strict mode, and I am able to replicate this in --!strict mode, though not --!nonstrict. If you could provide a reproduction RBXL where this happens in --!nonstrict mode that would be appreciated, as I cannot seem to get this same error.
Previously, this did not happen in nonstrict mode, and there is no discernable benefit to this behavior, so I can only assume that this is a bug.
When you write:
local _ = script.TestModel.Part
In the new solver, Luau is aware of your specific data model: it’s able to see that there’s an Instance TestModel that’s a child of your script, and it has a child called Part. If you wrote something like:
local _ = script.TestModel.DoesntExist
… you’ll get an error if TestModel didn’t have a child named DoesntExist.
However when you write:
local Mdl : Model = script.TestModel
local Prt : Part = Mdl.Part
You have told Luau “this is any particular Model,” you’re hiding the information that it’s a specific model. It might be one that doesn’t have a child named Part.
As I was trying to figure out how exactly to replicate this in other place files, I realized that this was not a bug but rather the result of user error on my part, I’m not sure how this happened but Workspace property UseNewLuauTypeSolver was somehow turned to Disabled which was the cause of this behavior manifesting, to be honest I forgot this property even existed, but I could indeed replicate it in any place by setting it from Enabled to Disabled. So no action is needed, sorry for the false report!
I suppose I should’ve thought of that, I don’t use --!strict very often so I wasn’t immediately familiar with this behavior, and in hindsight it does make sense for a strict type checking mode.