-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Better handle free vars and unknown types in abstract defs #16407
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
base: master
Are you sure you want to change the base?
Better handle free vars and unknown types in abstract defs #16407
Conversation
| end | ||
|
|
||
| abstract def abi_info(atys : Array(LLVM::Type), rty : LLVM::Type, ret_def : Bool, context : Context) | ||
| abstract def abi_info(atys : Array(LLVM::Type), rty : LLVM::Type, ret_def : Bool, context : LLVM::Context) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now that we're validating these, it errored that it didn't know what Context is.
| return false | ||
| end | ||
|
|
||
| return true if restriction.global? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
At this time all the types have been defined, so I don't really know what this is supposed to do. I would expect to see an error in either abstract def here:
abstract class Foo
abstract def foo(x : Int32)
abstract def bar(x : ::A)
end
class Bar < Foo
def foo(x : ::A); end
def bar(x : Int32); end
endThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It was a way to retain current behavior, as without you get a lot of spec failures:
9) Codegen: is_a? evaluates method on filtered union type 3
In src/crystal/event_loop/polling.cr:255:21
255 | def read(socket : ::Socket, slice : Bytes) : Int32
^-------
Error: undefined constant ::Socket from src/compiler/crystal/semantic/ast.cr:6:7 in 'raise'
from src/compiler/crystal/semantic/ast.cr:5:5 in 'raise'
from src/compiler/crystal/semantic/abstract_def_checker.cr:461:5 in 'report_error'
from src/compiler/crystal/semantic/abstract_def_checker.cr:335:5 in 'report_undefined_type'
from src/compiler/crystal/semantic/abstract_def_checker.cr:272:27 in 'check_arg'
from src/compiler/crystal/semantic/abstract_def_checker.cr:203:29 in 'implements?'
from src/compiler/crystal/semantic/abstract_def_checker.cr:92:20 in 'check_implemented_in_subtypes'
from src/compiler/crystal/semantic/abstract_def_checker.cr:79:9 in 'check_single'
from src/compiler/crystal/semantic/abstract_def_checker.cr:38:7 in 'check_single'
from src/compiler/crystal/semantic/abstract_def_checker.cr:38:7 in 'check_single'
from src/compiler/crystal/semantic/abstract_def_checker.cr:38:7 in 'run'
from src/compiler/crystal/progress_tracker.cr:23:20 in 'top_level_semantic'
from src/compiler/crystal/semantic.cr:22:23 in 'semantic:cleanup'
from src/compiler/crystal/compiler.cr:229:16 in 'compile'
from src/process/shell.cr:14:5 in 'run'
from spec/compiler/codegen/is_a_spec.cr:159:5 in '->'
from src/spec/example.cr:50:13 in 'internal_run'
from src/spec/example.cr:38:16 in 'run'
from src/spec/context.cr:20:23 in 'run'
from src/spec/context.cr:20:23 in '->'
from src/crystal/at_exit_handlers.cr:18:17 in 'main'
from src/crystal/system/unix/main.cr:10:3 in 'main'
from /usr/lib/libc.so.6 in '??'
from /usr/lib/libc.so.6 in '__libc_start_main'
from .build/compiler_spec in '_start'
from ???But taking a second look, I think it's just another case similar to the LLVM Context. Maybe a question for @ysbaddaden given he's more familiar with this part of the code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The abstract EventLoop interface expects that the ::Socket type may not be defined, because we must always require "crystal/event_loop" but ::Socket is only defined when we explicitly require "socket".
IMO this should be legal with or without a return type in the abstract def, same goes for more specific pairs like |
|
I reverted 9e97b5b, but kept the specs/added a few more. This bring it back with behavior that exists on |
Fixes #10699
I broke out the rescue blocks into one for each side, removing the logic that always just defaulted to
trueif there was a type lookup error. It'll now properly throw an error if one side has a type that doesn't resolve. E.g. example one in the originally issue. This PR does NOT handle the case where both side are invalid types, but could change this as a follow up if we wanted too.A type is assumed to be resolvable if it is a free var, global, is a generic type var, or is not a
Path. This handles the second example in the original issue. It's still not super strict, as as it stands, the logic allows using a diff free var name, or really even justdef foo(x)to satisfyabstract def foo(x : U) : U forall U. This satisfies my use case at least by ensuring at least oneT.classoverload exists.EDIT:
Moving this to a draft,abstract def get_env(type : Int32)shouldn't be valid givenabstract def get_env(type : T.class) : T forall T.