Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Interface type variable is not resolved as a nested type alias #863

Open
Andre-LA opened this issue Nov 27, 2024 · 3 comments
Open

Interface type variable is not resolved as a nested type alias #863

Andre-LA opened this issue Nov 27, 2024 · 3 comments
Labels
semantics Unexpected or unsound behaviors

Comments

@Andre-LA
Copy link

Andre-LA commented Nov 27, 2024

local interface A<T> -- local record A<T> also fails
   type MyT = T
end

local a: A<number>
@hishamhm hishamhm added the bug Something isn't working label Dec 18, 2024
@hishamhm
Copy link
Member

hishamhm commented Jan 8, 2025

This no longer crashes, but it does report unknown type T.

The interaction of type variables and public nested types does pose a problem... what is really the type A.MyT? It leaks an unresolved type variable, and so it seems this should not be allowed.

@hishamhm hishamhm changed the title Assertion fails when adding a type alias to a generic type inside a interface or record Interface type variable is not resolved as a nested type alias Jan 10, 2025
@hishamhm hishamhm added semantics Unexpected or unsound behaviors and removed bug Something isn't working labels Jan 10, 2025
@hishamhm
Copy link
Member

I'm downgrading this from "bug" to "semantics issue" since it's not clear what the desired behavior is.

@Andre-LA
Copy link
Author

Andre-LA commented Jan 10, 2025

I'm downgrading this from "bug" to "semantics issue" since it's not clear what the desired behavior is.

Well, I can only think in using aliased types, like this:

-- The following code is accepted by tl 0.24.2

local record Option<T>
	value: T
	mt: metatable<Option>
end

Option.mt = { __index = Option }

function Option.new<T>(v: T): Option<T>
	return setmetatable({ value = v }, Option.mt)
end

function Option:unwrap_or<T>(default: T): T
	return self.value or default
end

local interface Handler<T>
	-- let's say "handle" returns a duple: an option result and a error string,
	-- however, the developer abstracts that duple as a Result type.

	type Result = { Option<T>, string }
	handle: function(): Result
end

local record InputHandler is Handler<integer>
	-- now: InputHandler.Result exists! And it's an { Option<integer>, string }
end

-- let's test that:
--[[
local x: InputHandler.Result = { Option.new(10), nil } -- no problem
local y: InputHandler.Result = { Option.new('hello'), nil } -- argument 1: got string "hello", expected integer
--]]

function InputHandler.handle(): Handler.Result -- can't be InputHandler.Result
	-- if I return InputHandler.Result here though, it get that error:
	-- type signature of 'handle' does not match its declaration in InputHandler: return 1: InputHandler.Result is not a Result
	
	-- so we need to use Handler.Result, however that does not ensure the types are correct

	local numstr = io.read()
	if not numstr then
		return { Option.new(nil), "could not read input" }
	end

	local num = tonumber(numstr)
	if not num then
		return { Option.new(nil), "could not read number from input" }
	end

	-- return { Option.new('hello'), nil } -- that's accepted, it just expects Option<T>
	return { Option.new(math.floor(num)), nil }
end

-- test
local result = InputHandler.handle()
print(result[1]:unwrap_or(-100), result[2])

I think that InputHandler.Result being { Option<integer>, string } useful (or at least "pretty cool", because it triggers an compile error like the y variable in the middle.

However, indeed Handler.Result doesn't makes sense here I think, and I'm kinda cherry-picking this case, so I'm not sure if this opens more problems later.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
semantics Unexpected or unsound behaviors
Projects
None yet
Development

No branches or pull requests

2 participants