Accepts literal `null` as a receiver of `==`, `!=` and `is_same_instance`.
This could help to finish #1041
Does people need other methods of Object available for `null`?
Pull-Request: #1082
Reviewed-by: Lucas Bajolet <r4pass@hotmail.com>
Reviewed-by: Etienne M. Gagnon <egagnon@j-meg.com>
Reviewed-by: Alexis Laferrière <alexis.laf@xymus.net>
if args.first.mcasttype isa MNullableType or args.first.mcasttype isa MNullType and consider_null then
# The reciever is potentially null, so we have to 3 cases: ==, != or NullPointerException
self.add("if ({args.first} == NULL) \{ /* Special null case */")
- if m.name == "==" then
+ if m.name == "==" or m.name == "is_same_instance" then
assert res != null
if args[1].mcasttype isa MNullableType then
self.add("{res} = ({args[1]} == NULL);")
var res: nullable RuntimeVariable = null
var recv = arguments.first
var consider_null = not self.compiler.modelbuilder.toolcontext.opt_no_check_null.value or mmethod.name == "==" or mmethod.name == "!="
- var maybenull = recv.mcasttype isa MNullableType and consider_null
+ var maybenull = (recv.mcasttype isa MNullableType or recv.mcasttype isa MNullType) and consider_null
if maybenull then
self.add("if ({recv} == NULL) \{")
- if mmethod.name == "==" then
+ if mmethod.name == "==" or mmethod.name == "is_same_instance" then
res = self.new_var(bool_type)
var arg = arguments[1]
if arg.mcasttype isa MNullableType then
else
self.add("\{")
end
- if not self.compiler.modelbuilder.toolcontext.opt_no_shortcut_equate.value and (mmethod.name == "==" or mmethod.name == "!=") then
- if res == null then res = self.new_var(bool_type)
- # Recv is not null, thus is arg is, it is easy to conclude (and respect the invariants)
+ if not self.compiler.modelbuilder.toolcontext.opt_no_shortcut_equate.value and (mmethod.name == "==" or mmethod.name == "!=" or mmethod.name == "is_same_instance") then
+ # Recv is not null, thus if arg is, it is easy to conclude (and respect the invariants)
var arg = arguments[1]
if arg.mcasttype isa MNullType then
- if mmethod.name == "==" then
- self.add("{res} = 0; /* arg is null but recv is not */")
- else
+ if res == null then res = self.new_var(bool_type)
+ if mmethod.name == "!=" then
self.add("{res} = 1; /* arg is null and recv is not */")
+ else # `==` and `is_same_instance`
+ self.add("{res} = 0; /* arg is null but recv is not */")
end
self.add("\}") # closes the null case
self.add("if (0) \{") # what follow is useless, CC will drop it
fun send_commons(mproperty: MMethod, args: Array[Instance], mtype: MType): nullable Instance
do
if mtype isa MNullType then
- if mproperty.name == "==" then
+ if mproperty.name == "==" or mproperty.name == "is_same_instance" then
return self.bool_instance(args[0] == args[1])
else if mproperty.name == "!=" then
return self.bool_instance(args[0] != args[1])
var anchor = callsite.anchor
if anchor != null then mtype = mtype.anchor_to(callsite.mmodule, anchor)
mtype = mtype.as_notnullable
- assert mtype isa MClassType
- mtype = mtype.mclass.intro.bound_mtype
+ if mtype isa MClassType then mtype = mtype.mclass.intro.bound_mtype
var mproperty = callsite.mproperty
var res = live_targets_cache[mtype, mproperty]
if res != null then return res
#debug("recv: {recvtype} (aka {unsafe_type})")
if recvtype isa MNullType then
- self.error(node, "Error: Method '{name}' call on 'null'.")
- return null
+ # `null` only accepts some methods of object.
+ if name == "==" or name == "!=" or name == "is_same_instance" then
+ unsafe_type = mmodule.object_type.as_nullable
+ else
+ self.error(node, "Error: Method '{name}' call on 'null'.")
+ return null
+ end
end
var mproperty = self.try_get_mproperty_by_name2(node, unsafe_type, name)
self.read_type = readtype
- if readtype isa MNullType then
- v.error(self, "Error: Method '{reassign_name}' call on 'null'.")
- return null
- end
-
var callsite = v.get_method(self, readtype, reassign_name, false)
if callsite == null then return null # Skip error
self.reassign_callsite = callsite
var name = self.property_name
if recvtype == null then return # Forward error
- if recvtype isa MNullType then
- v.error(self, "Error: Method '{name}' call on 'null'.")
- return
- end
var callsite = v.get_method(self, recvtype, name, self.n_expr isa ASelfExpr)
if callsite == null then return
var name = self.property_name
if recvtype == null then return # Forward error
- if recvtype isa MNullType then
- v.error(self, "Error: Method '{name}' call on 'null'.")
- return
- end
var for_self = self.n_expr isa ASelfExpr
var callsite = v.get_method(self, recvtype, name, for_self)
--- /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
+
+class A
+ redef fun output do 10.output
+end
+
+var a: Object = new A
+var na: nullable Object = new A
+var nn: nullable Object = null
+
+(null == a).output
+(null == na).output
+(null == nn).output
+(null == null).output
+
+'\n'.output
+
+null.is_same_instance(a).output
+null.is_same_instance(na).output
+null.is_same_instance(nn).output
+null.is_same_instance(null).output
+
+'\n'.output
+
+(null != a).output
+(null != na).output
+(null != nn).output
+(null != null).output
--- /dev/null
+base_null.nit:28,2--13: Warning: expression is not null, since it is a `null`.
+base_null.nit:42,2--13: Warning: expression is not null, since it is a `null`.
+false
+false
+true
+true
+
+false
+false
+true
+true
+
+true
+true
+false
+false