This was an old bug causing the use of ``` ` ``` within a foreign code block to break the block. Example:
~~~~
fun foo `{
// Some comment on entity `foo` would prevent the whole block to be recognize
`}
~~~~
Pull-Request: #847
Reviewed-by: Lucas Bajolet <r4pass@hotmail.com>
Reviewed-by: Alexandre Terrasa <alexandre@moz-code.org>
Reviewed-by: Jean Privat <jean@pryen.org>
n_args.n_exprs.add_all(args)
end
self.callsite = callsite
- self.mtype = callsite.recv
+ self.recvtype = callsite.recv.as(MClassType)
+ if callsite.mproperty.is_new then
+ self.mtype = callsite.msignature.return_mtype
+ else
+ self.mtype = callsite.recv
+ end
self.is_typed = true
end
end
if modelbuilder.mpropdef2npropdef.has_key(self) then
var npropdef = modelbuilder.mpropdef2npropdef[self]
return npropdef.can_inline
- else if self.mproperty.name == "init" then
+ else if self.mproperty.is_root_init then
# Automatic free init is always inlined since it is empty or contains only attribtes assigments
return true
else
self.compile_parameter_check(v, arguments)
npropdef.compile_to_c(v, self, arguments)
v.current_node = oldnode
- else if self.mproperty.name == "init" then
+ else if self.mproperty.is_root_init then
var nclassdef = modelbuilder.mclassdef2nclassdef[self.mclassdef]
var oldnode = v.current_node
v.current_node = nclassdef
var ret = mpropdef.msignature.return_mtype
if ret != null then
ret = v.resolve_for(ret, arguments.first)
- else if mpropdef.mproperty.is_new then
- ret = arguments.first.mcasttype
end
if pname != "==" and pname != "!=" then
v.adapt_signature(mpropdef, arguments)
else if pname == "atoi" then
v.ret(v.new_expr("atoi({arguments[0]});", ret.as(not null)))
return true
- else if pname == "init" then
+ else if pname == "new" then
v.ret(v.new_expr("(char*)nit_alloc({arguments[1]})", ret.as(not null)))
return true
end
redef class ANewExpr
redef fun expr(v)
do
- var mtype = self.mtype.as(MClassType)
+ var mtype = self.recvtype
+ assert mtype != null
var recv
var ctype = mtype.ctype
if mtype.mclass.name == "NativeArray" then
var res: nullable RuntimeVariable
var ret = m.intro.msignature.return_mtype
- if m.is_new then
- ret = args.first.mtype
- res = self.new_var(ret)
- else if ret == null then
+ if ret == null then
res = null
else
ret = self.resolve_for(ret, args.first)
if ret != null then
ret = v.resolve_for(ret, selfvar)
sig.append("{ret.ctype} ")
- else if mmethoddef.mproperty.is_new then
- ret = recv
- sig.append("{ret.ctype} ")
else
sig.append("void ")
end
redef fun call(v: VISITOR, arguments: Array[RuntimeVariable]): nullable RuntimeVariable
do
var ret = self.mmethoddef.msignature.return_mtype
- if self.mmethoddef.mproperty.is_new then
- ret = recv
- end
if ret != null then
ret = v.resolve_for(ret, arguments.first)
end
compiler.do_property_coloring
for m in mainmodule.in_importation.greaters do
for mclass in m.intro_mclasses do
- if mclass.kind == abstract_kind or mclass.kind == interface_kind then continue
+ #if mclass.kind == abstract_kind or mclass.kind == interface_kind then continue
compiler.compile_class_to_c(mclass)
end
end
var res: nullable RuntimeVariable
var msignature = mmethod.intro.msignature.resolve_for(mmethod.intro.mclassdef.bound_mtype, mmethod.intro.mclassdef.bound_mtype, mmethod.intro.mclassdef.mmodule, true)
var ret = msignature.return_mtype
- if mmethod.is_new then
- ret = arguments.first.mtype
- res = self.new_var(ret)
- else if ret == null then
+ if ret == null then
res = null
else
res = self.new_var(ret)
var res: nullable RuntimeVariable
var ret = mmethoddef.msignature.return_mtype
- if mmethoddef.mproperty.is_new then
- ret = arguments.first.mtype
- res = self.new_var(ret)
- else if ret == null then
+ if ret == null then
res = null
else
ret = ret.resolve_for(mmethoddef.mclassdef.bound_mtype, mmethoddef.mclassdef.bound_mtype, mmethoddef.mclassdef.mmodule, true)
var ret = msignature.return_mtype
if ret != null then
sig.append("{ret.ctype} ")
- else if mmethoddef.mproperty.is_new then
- ret = recv
- sig.append("{ret.ctype} ")
else
sig.append("void ")
end
var ret = msignature.return_mtype
if ret != null then
sig.append("{ret.ctype} ")
- else if mmethoddef.mproperty.is_new then
- ret = recv
- sig.append("{ret.ctype} ")
else
sig.append("void ")
end
var v = self.new_visitor
var rta = runtime_type_analysis
- var is_dead = mclass.kind == abstract_kind or mclass.kind == interface_kind
+ var is_dead = false # mclass.kind == abstract_kind or mclass.kind == interface_kind
if not is_dead and rta != null and not rta.live_classes.has(mclass) and mtype.ctype == "val*" and mclass.name != "NativeArray" then
is_dead = true
end
print "Error, invalid propdef to call at runtime !"
return null
end
- else if mproperty.name == "init" then
+ else if mproperty.is_root_init then
var nclassdef = self.modelbuilder.mclassdef2nclassdef[mpropdef.mclassdef]
self.parameter_check(nclassdef, mpropdef, args)
return nclassdef.call(self, mpropdef, args)
var npropdef = self.modelbuilder.mpropdef2npropdef[mpropdef]
self.parameter_check(npropdef, mpropdef, args)
return npropdef.call(self, mpropdef, args)
- else if mproperty.name == "init" then
+ else if mproperty.is_root_init then
var nclassdef = self.modelbuilder.mclassdef2nclassdef[mpropdef.mclassdef]
self.parameter_check(nclassdef, mpropdef, args)
return nclassdef.call(self, mpropdef, args)
return v.bool_instance(args[0].to_f.is_inf != 0)
end
else if cname == "NativeString" then
- if pname == "init" then
+ if pname == "new" then
return v.native_string_instance("!" * args[1].to_i)
end
var recvval = args.first.val.as(Buffer)
else if pname == "calloc_string" then
return v.native_string_instance("!" * args[1].to_i)
else if cname == "NativeArray" then
- if pname == "init" then
+ if pname == "new" then
var val = new Array[Instance].filled_with(v.null_instance, args[1].to_i)
return new PrimitiveInstance[Array[Instance]](args[0].mtype, val)
end
redef class ANewExpr
redef fun expr(v)
do
- var mtype = v.unanchor_type(self.mtype.as(not null))
+ var mtype = v.unanchor_type(self.recvtype.as(not null))
var recv: Instance = new MutableInstance(mtype)
v.init_instance(recv)
var args = v.varargize(callsite.mpropdef, recv, self.n_args.n_exprs)
# Alias for `name`
redef fun to_s do return self.name
- # The definition that introduced the class
- # Warning: the introduction is the first `MClassDef` object associated
- # to self. If self is just created without having any associated
- # definition, this method will abort
- fun intro: MClassDef
- do
- assert has_a_first_definition: not mclassdefs.is_empty
- return mclassdefs.first
- end
+ # The definition that introduces the class.
+ #
+ # Warning: such a definition may not exist in the early life of the object.
+ # In this case, the method will abort.
+ var intro: MClassDef
# Return the class `self` in the class hierarchy of the module `mmodule`.
#
self.location = location
mmodule.mclassdefs.add(self)
mclass.mclassdefs.add(self)
+ if mclass.intro_mmodule == mmodule then
+ assert not isset mclass._intro
+ mclass.intro = self
+ end
self.to_s = "{mmodule}#{mclass}"
end
# The other are redefinitions (in refinements and in subclasses)
var mpropdefs = new Array[MPROPDEF]
- # The definition that introduced the property
- # Warning: the introduction is the first `MPropDef` object
- # associated to self. If self is just created without having any
- # associated definition, this method will abort
- fun intro: MPROPDEF do return mpropdefs.first
+ # The definition that introduces the property.
+ #
+ # Warning: such a definition may not exist in the early life of the object.
+ # In this case, the method will abort.
+ var intro: MPROPDEF
redef fun model do return intro.model
self.location = location
mclassdef.mpropdefs.add(self)
mproperty.mpropdefs.add(self)
+ if mproperty.intro_mclassdef == mclassdef then
+ assert not isset mproperty._intro
+ mproperty.intro = self
+ end
self.to_s = "{mclassdef}#{mproperty}"
end
for mprop in props do
if not mtype.has_mproperty(mmodule, mprop) then continue
if not mmodule.is_visible(mprop.intro_mclassdef.mmodule, mprop.visibility) then continue
+
+ # new-factories are invisible outside of the class
+ if mprop isa MMethod and mprop.is_new and (not mtype isa MClassType or mprop.intro_mclassdef.mclass != mtype.mclass) then
+ continue
+ end
+
if res == null then
res = mprop
continue
name = "init"
name_node = n_kwinit
else if n_kwnew != null then
- name = "init"
+ name = "new"
name_node = n_kwnew
else
abort
modelbuilder.error(node, "Redef error: {mpropdef} redefines {mpropdef.mproperty.intro} with {param_names.length} parameter(s), {msignature.arity} expected. Signature is {mpropdef}{msignature}")
return
end
- else if mpropdef.mproperty.is_init then
+ else if mpropdef.mproperty.is_init and not mpropdef.mproperty.is_new then
# FIXME UGLY: inherit signature from a super-constructor
for msupertype in mclassdef.supertypes do
msupertype = msupertype.anchor_to(mmodule, mclassdef.bound_mtype)
mparameters.add(mparameter)
end
+ # In `new`-factories, the return type is by default the classtype.
+ if ret_type == null and mpropdef.mproperty.is_new then ret_type = mclassdef.mclass.mclass_type
+
msignature = new MSignature(mparameters, ret_type)
mpropdef.msignature = msignature
mpropdef.is_abstract = self.get_single_annotation("abstract", modelbuilder) != null
# `MClassDef`
#
# * labels: `MClassDef`, `model_name` and `MEntity`.
-# * `is_intro`: Does this definition introduce the class?
# * `location`: origin of the definition. SEE: `Location.to_s`
# * `(:MClassDef)-[:BOUNDTYPE]->(:MClassType)`: bounded type associated to the
# classdef.
# * labels: `MPropDef`, `model_name` and `MEntity`. Must also have `MMethodDef`,
# `MAttributeDef` or `MVirtualTypeDef`, depending on the class of the
# represented entity.
-# * `is_intro`: Does this definition introduce the property?
# * `location`: origin of the definition. SEE: `Location.to_s`.
# * `(:MPropDef)-[:DEFINES]->(:MProperty)`: associated property.
#
private fun mclassdef_node(mclassdef: MClassDef): NeoNode do
var node = make_node(mclassdef)
node.labels.add "MClassDef"
- node["is_intro"] = mclassdef.is_intro
node["location"] = mclassdef.location.to_s
node.out_edges.add(new NeoEdge(node, "BOUNDTYPE", to_node(mclassdef.bound_mtype)))
node.out_edges.add(new NeoEdge(node, "MCLASS", to_node(mclassdef.mclass)))
end
mentities[node] = mprop
set_doc(node, mprop)
- for npropdef in node.in_nodes("DEFINES") do
- var mpropdef = to_mpropdef(model, npropdef)
- if npropdef["is_intro"].as(Bool) then
- mprop.mpropdefs.unshift mpropdef
- else
- mprop.mpropdefs.add mpropdef
- end
- end
return mprop
end
private fun mpropdef_node(mpropdef: MPropDef): NeoNode do
var node = make_node(mpropdef)
node.labels.add "MPropDef"
- node["is_intro"] = mpropdef.is_intro
node["location"] = mpropdef.location.to_s
node.out_edges.add(new NeoEdge(node, "DEFINES", to_node(mpropdef.mproperty)))
if mpropdef isa MMethodDef then
return
end
- var meth_name = "init"
+ var meth_name = "new"
var meth = toolcontext.modelbuilder.try_get_mproperty_by_name2( self,
mmodule, mtype, meth_name )
if meth == null then
+ meth_name = "init"
+ meth = toolcontext.modelbuilder.try_get_mproperty_by_name2( self,
+ mmodule, mtype, meth_name )
+ end
+
+ if meth == null then
toolcontext.error(location, "Method {meth_name} not found in {n_type.collect_text}." )
return
end
if not modelbuilder.mpropdef2npropdef.has_key(mmethoddef) then
# It is an init for a class?
- if mmeth.name == "init" then
+ if mmeth.is_root_init then
var nclassdef = self.modelbuilder.mclassdef2nclassdef[mmethoddef.mclassdef]
assert mmethoddef == nclassdef.mfree_init
end
end
- if mmeth.is_new then
- v.add_type(v.receiver)
- else if mmethoddef.is_intern or mmethoddef.is_extern then
+ if mmethoddef.is_intern or mmethoddef.is_extern then
# UGLY: We force the "instantation" of the concrete return type if any
var ret = mmethoddef.msignature.return_mtype
if ret != null and ret isa MClassType and ret.mclass.kind != abstract_kind and ret.mclass.kind != interface_kind then
redef class ANewExpr
redef fun accept_rapid_type_visitor(v)
do
- var mtype = self.mtype.as(MClassType)
+ var mtype = self.recvtype.as(not null)
v.add_type(mtype)
v.add_callsite(callsite)
end
selfvariable.declared_type = mclass.mclass_type
var mprop = mpropdef.mproperty
- if mprop isa MMethod and mprop.is_toplevel then
+ if mprop isa MMethod and (mprop.is_toplevel or mprop.is_new) then
is_toplevel_context = true
end
end
end
var mproperty = self.try_get_mproperty_by_name2(node, unsafe_type, name)
+ if name == "new" and mproperty == null then
+ name = "init"
+ mproperty = self.try_get_mproperty_by_name2(node, unsafe_type, name)
+ end
+
if mproperty == null then
#self.modelbuilder.error(node, "Type error: property {name} not found in {unsafe_type} (ie {recvtype})")
if recv_is_self then
# The constructor invoked by the new.
var callsite: nullable CallSite
+ # The designated type
+ var recvtype: nullable MClassType
+
redef fun accept_typing(v)
do
var recvtype = v.resolve_mtype(self.n_type)
if recvtype == null then return
- self.mtype = recvtype
if not recvtype isa MClassType then
if recvtype isa MNullableType then
v.error(self, "Type error: cannot instantiate the formal type {recvtype}.")
return
end
- else
- if recvtype.mclass.kind == abstract_kind then
- v.error(self, "Cannot instantiate abstract class {recvtype}.")
- return
- else if recvtype.mclass.kind == interface_kind then
- v.error(self, "Cannot instantiate interface {recvtype}.")
- return
- end
end
+ self.recvtype = recvtype
+
var name: String
var nid = self.n_id
if nid != null then
name = nid.text
else
- name = "init"
+ name = "new"
end
var callsite = v.get_method(self, recvtype, name, false)
if callsite == null then return
+ if not callsite.mproperty.is_new then
+ var kind = recvtype.mclass.kind
+ if kind != concrete_kind then
+ v.error(self, "Cannot instantiate {kind} {recvtype}.")
+ return
+ end
+ self.mtype = recvtype
+ else
+ self.mtype = callsite.msignature.return_mtype
+ assert self.mtype != null
+ end
+
self.callsite = callsite
if not callsite.mproperty.is_init_for(recvtype.mclass) then
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import kernel
+
+interface A
+ new do return new B(1)
+ new n2 do return new B(2)
+ new n3: B do return new B(3)
+ new n4: Int do return 4
+ new n5: Int do return new B.ni(5)
+ #alt1#new n do return 5
+ #alt2#new n do 0.output
+ #alt3#new n do return self
+ #alt4#new n: Int do return object_id
+end
+
+class B
+ super A
+ var i: Int
+ redef fun output do
+ 'B'.output
+ i.output
+ end
+ new n2 do return new B(22)
+ new n3: B do return new B(33)
+ new n4: Int do return 44
+ new n5: Int do return new B.ni(55)
+ new ni(i: Int): Int do return i*10
+end
+
+class C
+ super B
+ new(i: Int): B do return new B(i)
+ redef fun output do
+ 'C'.output
+ i.output
+ end
+end
+
+redef class Int
+ new z do return 0
+ new a: A do return new A
+end
+
+(new A).output
+#alt5#(new A).i.output
+(new A.n2).output
+#alt6#(new A.n2).i.output
+(new A.n3).i.output
+(new A.n4).output
+(new A.n5).output
+#alt1-4#(new A.n).output
+
+'\n'.output
+
+(new B(11)).output
+(new B.n2).i.output
+(new B.n3).i.output
+(new B.n4).output
+(new B.n5).output
+(new B.ni(66)).output
+
+'\n'.output
+
+(new C(111)).output
+#alt7#(new C.n2).output
+
+'\n'.output
+
+#alt8#(new Int).output
+(new Int.z).output
+(new Int.a).output
--- /dev/null
+B1
+B2
+3
+4
+50
+
+B11
+22
+33
+44
+550
+660
+
+B111
+
+0
+B1
--- /dev/null
+alt/base_new_alt1.nit:23,18: Type error: expected A, got Int
--- /dev/null
+alt/base_new_alt2.nit:24,6: Control error: Reached end of function (a 'return' with a value was expected).
--- /dev/null
+alt/base_new_alt3.nit:25,18--21: Error: self cannot be used in top-level method.
--- /dev/null
+alt/base_new_alt4.nit:26,23--31: Error: 'object_id' is not a top-level method, thus need a receiver.
--- /dev/null
+alt/base_new_alt5.nit:58,1--9: Error: Method 'i' doesn't exists in A.
--- /dev/null
+alt/base_new_alt6.nit:60,1--12: Error: Method 'i' doesn't exists in A.
--- /dev/null
+alt/base_new_alt7.nit:78,2--9: Error: Method 'n2' doesn't exists in C.
--- /dev/null
+alt/base_new_alt8.nit:82,2--8: Cannot instantiate enum Int.
alt/error_needed_method_alt2.nit:47,10--27: Cannot instantiate interface Collection[Int].
-alt/error_needed_method_alt2.nit:47,1--40: Error: Method 'iterator' doesn't exists in Collection[Int].
-alt/error_needed_method_alt2.nit:47,1--40: Type Error: 'for' expects a type providing 'iterator' method, got 'Collection[Int]'.