Skip to content

Commit

Permalink
fix: ClassSpecialization should return Env
Browse files Browse the repository at this point in the history
which contains the newly created SkSpecializedClass
  • Loading branch information
yhara committed Sep 8, 2018
1 parent 83a375f commit 9c4af10
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 30 deletions.
28 changes: 17 additions & 11 deletions lib/shiika/program.rb
Expand Up @@ -658,42 +658,43 @@ def check_nonvar_arg_types(sk_method)

class AssignmentExpr < Expression
def calc_type!(env)
expr.add_type!(env)
newenv = expr.add_type!(env)
raise SkProgramError, "cannot assign Void value" if expr.type == TyRaw["Void"]
return newenv
end
end

class AssignLvar < AssignmentExpr
props varname: String, expr: Expression, isvar: :boolean

def calc_type!(env)
super
newenv = super
lvar = env.find_lvar(varname, allow_missing: true)
if lvar
if lvar.kind == :let
raise SkProgramError, "lvar #{varname} is read-only (missing `var`)"
end
unless env.conforms_to?(expr.type, lvar.type)
unless newenv.conforms_to?(expr.type, lvar.type)
raise SkTypeError, "the type of expr (#{expr.type}) does not conform to the type of lvar #{varname} (#{lvar.type})"
end
else
lvar = Lvar.new(varname, expr.type, (isvar ? :var : :let))
end
newenv = env.merge(:local_vars, {varname => lvar})
return newenv, expr.type
retenv = newenv.merge(:local_vars, {varname => lvar})
return retenv, expr.type
end
end

class AssignIvar < AssignmentExpr
props varname: String, expr: Expression

def calc_type!(env)
super
newenv = super
ivar = env.find_ivar(varname)
if ivar.type != expr.type # TODO: subtypes
raise SkTypeError, "ivar #{varname} of class #{env.sk_self} is #{ivar.type} but expr is #{expr.type}"
end
return env, expr.type
return newenv, expr.type
end
end

Expand Down Expand Up @@ -747,8 +748,12 @@ def calc_type!(env)
raise SkTypeError, "not a class: #{expr.inspect}" unless expr.type.is_a?(TyMeta)
expr.type.instance_type
}
create_specialized_class(env, base_class_name, type_args)
return env, TySpeMeta[base_class_name, type_args]
sp_cls, sp_meta = create_specialized_class(env, base_class_name, type_args)
newenv = env.merge(:sk_classes, {
sp_cls.name => sp_cls,
sp_meta.name => sp_meta.name,
})
return newenv, TySpeMeta[base_class_name, type_args]
end

private
Expand All @@ -758,9 +763,10 @@ def create_specialized_class(env, base_class_name, type_args)
gen_cls = env.find_class(base_class_name)
raise if !(SkGenericClass === gen_cls) &&
!(SkGenericMetaClass === gen_cls)
gen_cls.specialized_class(type_args, env)
sp_cls = gen_cls.specialized_class(type_args, env)
gen_meta = env.find_meta_class(base_class_name)
gen_meta.specialized_class(type_args, env)
sp_meta = gen_meta.specialized_class(type_args, env)
return sp_cls, sp_meta
end
end

Expand Down
46 changes: 27 additions & 19 deletions spec/program/type_check_spec.rb
Expand Up @@ -225,24 +225,32 @@ class C extends B; end
type!(src)
end

# it 'generic subclass of a non-generic class' do
# src = <<~EOD
# class A; end
# class B<T> extends A; end
# var x = A.new
# x = B<Int>.new
# EOD
# type!(src)
# end
#
# it 'generic subclass of a generic class (are not considered to be a subtype)' do
# src = <<~EOD
# class A<T>; end
# class B<T> extends A<T>; end
# var x = A<Int>.new
# x = B<Int>.new
# EOD
# expect{ type!(src) }.to raise_error(SkTypeError)
# end
it 'generic subclass of a non-generic class' do
src = <<~EOD
class A; end
class B<T> extends A; end
var x = A.new
x = B<Int>.new
EOD
type!(src)
end

it 'generic subclass of a generic class' do
src = <<~EOD
class A<T>; end
class B<T> extends A<T>; end
var x = A<Int>.new
x = B<Int>.new
EOD
type!(src)
end

it 'variance' do
src = <<~EOD
var x = Array<Object>.new
x = Array<Int>.new
EOD
expect{ type!(src) }.to raise_error(SkTypeError)
end
end
end

0 comments on commit 9c4af10

Please sign in to comment.