From 60feadd7fc3ea18e3b3de99c20364b8f47c81574 Mon Sep 17 00:00:00 2001 From: Jean Privat Date: Mon, 22 Jun 2009 12:07:50 -0400 Subject: [PATCH] syntax: if_false_variable_ctx Allow casts to be propagated in 'else' branches Example: if not a isa B then a.only_b_can_do # Static error else a.only_b_can_do # OK since current static type of a is B here end Signed-off-by: Jean Privat --- src/syntax/typing.nit | 67 ++++++++++++++++++++++++++++--------- tests/base_isa_cast3.nit | 60 +++++++++++++++++++++++++++++++++ tests/sav/base_isa_cast3.sav | 2 ++ tests/sav/base_isa_cast3_alt1.sav | 1 + tests/sav/base_isa_cast3_alt2.sav | 1 + tests/sav/base_isa_cast3_alt3.sav | 1 + tests/sav/base_isa_cast3_alt4.sav | 1 + tests/sav/base_isa_cast3_alt5.sav | 1 + tests/sav/base_isa_cast3_alt6.sav | 1 + tests/sav/base_isa_cast3_alt7.sav | 1 + tests/sav/base_isa_cast3_alt8.sav | 1 + 11 files changed, 121 insertions(+), 16 deletions(-) create mode 100644 tests/base_isa_cast3.nit create mode 100644 tests/sav/base_isa_cast3.sav create mode 100644 tests/sav/base_isa_cast3_alt1.sav create mode 100644 tests/sav/base_isa_cast3_alt2.sav create mode 100644 tests/sav/base_isa_cast3_alt3.sav create mode 100644 tests/sav/base_isa_cast3_alt4.sav create mode 100644 tests/sav/base_isa_cast3_alt5.sav create mode 100644 tests/sav/base_isa_cast3_alt6.sav create mode 100644 tests/sav/base_isa_cast3_alt7.sav create mode 100644 tests/sav/base_isa_cast3_alt8.sav diff --git a/src/syntax/typing.nit b/src/syntax/typing.nit index 679b88e..f9d5eba 100644 --- a/src/syntax/typing.nit +++ b/src/syntax/typing.nit @@ -65,9 +65,14 @@ special AbsSyntaxVisitor private meth use_if_true_variable_ctx(e: PExpr) do var ctx = e.if_true_variable_ctx - if ctx != null then - variable_ctx = ctx - end + if ctx != null then variable_ctx = ctx + end + + # Make the if_false_variable_ctx of the expression effective + private meth use_if_false_variable_ctx(e: PExpr) + do + var ctx = e.if_false_variable_ctx + if ctx != null then variable_ctx = ctx end # Number of nested once @@ -303,6 +308,9 @@ redef class PExpr # The variable type information if current boolean expression is true readable private attr _if_true_variable_ctx: VariableContext + + # The variable type information if current boolean expression is false + readable private attr _if_false_variable_ctx: VariableContext end redef class AVardeclExpr @@ -420,24 +428,31 @@ redef class AIfExpr v.visit(n_expr) v.check_conform_expr(n_expr, v.type_bool) + # Prepare 'then' context v.use_if_true_variable_ctx(n_expr) - v.variable_ctx = v.variable_ctx.sub(n_then) - v.visit(n_then) + # Process the 'then' + if n_then != null then + v.variable_ctx = v.variable_ctx.sub(n_then) + v.visit(n_then) + end - if n_else == null then - # Restore variable ctx since the 'then' block is optional - v.variable_ctx = old_var_ctx - else - # Remember what appened in the 'then' - var then_var_ctx = v.variable_ctx - # Reset to process the 'else' - v.variable_ctx = old_var_ctx.sub(n_else) + # Remember what appened in the 'then' + var then_var_ctx = v.variable_ctx + + # Prepare 'else' context + v.variable_ctx = old_var_ctx + v.use_if_false_variable_ctx(n_expr) + + # Process the 'else' + if n_else != null then + v.variable_ctx = v.variable_ctx.sub(n_else) v.visit(n_else) - # Merge then and else in the old control_flow - old_var_ctx.merge2(then_var_ctx, v.variable_ctx) - v.variable_ctx = old_var_ctx end + + # Merge 'then' and 'else' contexts + old_var_ctx.merge2(then_var_ctx, v.variable_ctx) + v.variable_ctx = old_var_ctx _is_typed = true end end @@ -635,6 +650,7 @@ redef class AIfexprExpr v.use_if_true_variable_ctx(n_expr) v.visit(n_then) v.variable_ctx = old_var_ctx + v.use_if_false_variable_ctx(n_expr) v.visit(n_else) v.check_conform_expr(n_expr, v.type_bool) @@ -655,6 +671,20 @@ end redef class AOrExpr redef meth after_typing(v) do + var old_var_ctx = v.variable_ctx + + v.visit(n_expr) + v.use_if_false_variable_ctx(n_expr) + + v.visit(n_expr2) + if n_expr2.if_false_variable_ctx != null then + _if_false_variable_ctx = n_expr2.if_false_variable_ctx + else + _if_false_variable_ctx = v.variable_ctx + end + + v.variable_ctx = old_var_ctx + v.check_conform_expr(n_expr, v.type_bool) v.check_conform_expr(n_expr2, v.type_bool) _stype = v.type_bool @@ -690,6 +720,11 @@ redef class ANotExpr redef meth after_typing(v) do v.check_conform_expr(n_expr, v.type_bool) + + # Invert if_true/if_false information + _if_false_variable_ctx = n_expr._if_true_variable_ctx + _if_true_variable_ctx = n_expr._if_false_variable_ctx + _stype = v.type_bool _is_typed = true end diff --git a/tests/base_isa_cast3.nit b/tests/base_isa_cast3.nit new file mode 100644 index 0000000..e4c6f62 --- /dev/null +++ b/tests/base_isa_cast3.nit @@ -0,0 +1,60 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Copyright 2009 Jean Privat +# +# 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 + init do end +end + +class B +special A + meth foo(i: Int) do i.output + init do end +end + +var a: A = new B + +if a isa B then + a.foo(1) +else + #alt1#a.foo(-1) +end +#alt2#a.foo(-2) + +if not a isa B then + #alt3#a.foo(-3) +else + a.foo(2) +end +#alt4#a.foo(-4) + +if a isa B and false then + a.foo(3) +else + #alt5#a.foo(-5) +end +#alt6#a.foo(-6) + +if not a isa B or true then + #alt7#a.foo(-7) +else + a.foo(3) +end +#alt8#a.foo(-8) + + + diff --git a/tests/sav/base_isa_cast3.sav b/tests/sav/base_isa_cast3.sav new file mode 100644 index 0000000..1191247 --- /dev/null +++ b/tests/sav/base_isa_cast3.sav @@ -0,0 +1,2 @@ +1 +2 diff --git a/tests/sav/base_isa_cast3_alt1.sav b/tests/sav/base_isa_cast3_alt1.sav new file mode 100644 index 0000000..26dcf6f --- /dev/null +++ b/tests/sav/base_isa_cast3_alt1.sav @@ -0,0 +1 @@ +alt/base_isa_cast3_alt1.nit:34,2--9: Error: Method 'foo' doesn't exists in A. diff --git a/tests/sav/base_isa_cast3_alt2.sav b/tests/sav/base_isa_cast3_alt2.sav new file mode 100644 index 0000000..b3e455f --- /dev/null +++ b/tests/sav/base_isa_cast3_alt2.sav @@ -0,0 +1 @@ +alt/base_isa_cast3_alt2.nit:36,1--8: Error: Method 'foo' doesn't exists in A. diff --git a/tests/sav/base_isa_cast3_alt3.sav b/tests/sav/base_isa_cast3_alt3.sav new file mode 100644 index 0000000..ea93124 --- /dev/null +++ b/tests/sav/base_isa_cast3_alt3.sav @@ -0,0 +1 @@ +alt/base_isa_cast3_alt3.nit:39,2--9: Error: Method 'foo' doesn't exists in A. diff --git a/tests/sav/base_isa_cast3_alt4.sav b/tests/sav/base_isa_cast3_alt4.sav new file mode 100644 index 0000000..dcb1bf6 --- /dev/null +++ b/tests/sav/base_isa_cast3_alt4.sav @@ -0,0 +1 @@ +alt/base_isa_cast3_alt4.nit:43,1--8: Error: Method 'foo' doesn't exists in A. diff --git a/tests/sav/base_isa_cast3_alt5.sav b/tests/sav/base_isa_cast3_alt5.sav new file mode 100644 index 0000000..d524248 --- /dev/null +++ b/tests/sav/base_isa_cast3_alt5.sav @@ -0,0 +1 @@ +alt/base_isa_cast3_alt5.nit:48,2--9: Error: Method 'foo' doesn't exists in A. diff --git a/tests/sav/base_isa_cast3_alt6.sav b/tests/sav/base_isa_cast3_alt6.sav new file mode 100644 index 0000000..3c9fc0f --- /dev/null +++ b/tests/sav/base_isa_cast3_alt6.sav @@ -0,0 +1 @@ +alt/base_isa_cast3_alt6.nit:50,1--8: Error: Method 'foo' doesn't exists in A. diff --git a/tests/sav/base_isa_cast3_alt7.sav b/tests/sav/base_isa_cast3_alt7.sav new file mode 100644 index 0000000..a301a75 --- /dev/null +++ b/tests/sav/base_isa_cast3_alt7.sav @@ -0,0 +1 @@ +alt/base_isa_cast3_alt7.nit:53,2--9: Error: Method 'foo' doesn't exists in A. diff --git a/tests/sav/base_isa_cast3_alt8.sav b/tests/sav/base_isa_cast3_alt8.sav new file mode 100644 index 0000000..6fc6d23 --- /dev/null +++ b/tests/sav/base_isa_cast3_alt8.sav @@ -0,0 +1 @@ +alt/base_isa_cast3_alt8.nit:57,1--8: Error: Method 'foo' doesn't exists in A. -- 1.7.9.5