Skip to content

Commit 170f8e3

Browse files
authored
Merge pull request #532 from erg-lang/perf3
Avoid infinite recursion
2 parents 75535a7 + 87fb4cf commit 170f8e3

File tree

15 files changed

+840
-468
lines changed

15 files changed

+840
-468
lines changed

Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,3 +97,7 @@ path = "src/lib.rs"
9797

9898
# [profile.release]
9999
# panic = 'abort'
100+
101+
[profile.opt-with-dbg]
102+
inherits = "release"
103+
debug = true

crates/erg_common/error.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -753,7 +753,10 @@ impl SubMessage {
753753
gutter_color,
754754
);
755755
cxt.push_str(&" ".repeat(lineno.to_string().len()));
756-
cxt.push_str_with_color(mark.repeat(cmp::max(1, codes[i].len())), err_color);
756+
cxt.push_str_with_color(
757+
mark.repeat(cmp::max(1, codes.get(i).map_or(1, |code| code.len()))),
758+
err_color,
759+
);
757760
cxt.push_str("\n");
758761
}
759762
cxt.push_str("\n");

crates/erg_common/traits.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -517,6 +517,7 @@ pub trait LimitedDisplay {
517517
self.limited_fmt(&mut s, -1).unwrap();
518518
s
519519
}
520+
const DEFAULT_LIMIT: isize = 10;
520521
}
521522

522523
#[derive(Debug, PartialEq, Eq, Clone, Copy)]

crates/erg_compiler/context/compare.rs

Lines changed: 50 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -359,7 +359,11 @@ impl Context {
359359
/// 単一化、評価等はここでは行わない、スーパータイプになる **可能性があるか** だけ判定する
360360
/// ので、lhsが(未連携)型変数の場合は単一化せずにtrueを返す
361361
pub(crate) fn structural_supertype_of(&self, lhs: &Type, rhs: &Type) -> bool {
362-
set_recursion_limit!(false, 128);
362+
set_recursion_limit!(
363+
panic,
364+
"recursion limit exceed: structural_supertype_of({lhs}, {rhs})",
365+
128
366+
);
363367
match (lhs, rhs) {
364368
// Proc :> Func if params are compatible
365369
// * default params can be omitted (e.g. (Int, x := Int) -> Int <: (Int) -> Int)
@@ -409,45 +413,48 @@ impl Context {
409413
.return_t
410414
.clone()
411415
.replace_params(rs.param_names(), ls.param_names());
412-
let return_t_judge = self.supertype_of(&ls.return_t, &rhs_ret); // covariant
413-
let non_defaults_judge = if let Some(r_var) = rs.var_params.as_deref() {
414-
ls.non_default_params
415-
.iter()
416-
.zip(repeat(r_var))
417-
.all(|(l, r)| self.subtype_of(l.typ(), r.typ()))
418-
} else {
419-
let rs_params = if !ls.is_method() && rs.is_method() {
420-
rs.non_default_params
416+
let return_t_judge = || self.supertype_of(&ls.return_t, &rhs_ret); // covariant
417+
let non_defaults_judge = || {
418+
if let Some(r_var) = rs.var_params.as_deref() {
419+
ls.non_default_params
421420
.iter()
422-
.skip(1)
423-
.chain(&rs.default_params)
421+
.zip(repeat(r_var))
422+
.all(|(l, r)| self.subtype_of(l.typ(), r.typ()))
424423
} else {
425-
#[allow(clippy::iter_skip_zero)]
426-
rs.non_default_params
424+
let rs_params = if !ls.is_method() && rs.is_method() {
425+
rs.non_default_params
426+
.iter()
427+
.skip(1)
428+
.chain(&rs.default_params)
429+
} else {
430+
#[allow(clippy::iter_skip_zero)]
431+
rs.non_default_params
432+
.iter()
433+
.skip(0)
434+
.chain(&rs.default_params)
435+
};
436+
ls.non_default_params
427437
.iter()
428-
.skip(0)
429-
.chain(&rs.default_params)
430-
};
431-
ls.non_default_params
432-
.iter()
433-
.zip(rs_params)
434-
.all(|(l, r)| self.subtype_of(l.typ(), r.typ()))
438+
.zip(rs_params)
439+
.all(|(l, r)| self.subtype_of(l.typ(), r.typ()))
440+
}
441+
};
442+
let var_params_judge = || {
443+
ls.var_params
444+
.as_ref()
445+
.zip(rs.var_params.as_ref())
446+
.map(|(l, r)| self.subtype_of(l.typ(), r.typ()))
447+
.unwrap_or(true)
435448
};
436-
let var_params_judge = ls
437-
.var_params
438-
.as_ref()
439-
.zip(rs.var_params.as_ref())
440-
.map(|(l, r)| self.subtype_of(l.typ(), r.typ()))
441-
.unwrap_or(true);
442449
len_judge
443-
&& return_t_judge
444-
&& non_defaults_judge
445-
&& var_params_judge
450+
&& return_t_judge()
451+
&& non_defaults_judge()
452+
&& var_params_judge()
446453
&& default_check() // contravariant
447454
}
448455
// {Int} <: Obj -> Int
449-
(Subr(_) | Quantified(_), Refinement(refine))
450-
if rhs.singleton_value().is_some() && self.subtype_of(&refine.t, &ClassType) =>
456+
(Subr(_) | Quantified(_), Refinement(_refine))
457+
if rhs.singleton_value().is_some() && rhs.is_singleton_refinement_type() =>
451458
{
452459
let Ok(typ) = self.convert_tp_into_type(rhs.singleton_value().unwrap().clone())
453460
else {
@@ -457,7 +464,8 @@ impl Context {
457464
return false;
458465
};
459466
if let Some((_, __call__)) = ctx.get_class_attr("__call__") {
460-
self.supertype_of(lhs, &__call__.t)
467+
let call_t = __call__.t.clone().undoable_root();
468+
self.supertype_of(lhs, &call_t)
461469
} else {
462470
false
463471
}
@@ -767,10 +775,14 @@ impl Context {
767775
// Bool :> {2} == false
768776
// [2, 3]: {A: List(Nat) | A.prod() == 6}
769777
// List({1, 2}, _) :> {[3, 4]} == false
778+
// T :> {None} == T :> NoneType
770779
(l, Refinement(r)) => {
771780
// Type / {S: Set(Str) | S == {"a", "b"}}
772781
// TODO: GeneralEq
773782
if let Pred::Equal { rhs, .. } = r.pred.as_ref() {
783+
if rhs.is_none() {
784+
return self.supertype_of(lhs, &NoneType);
785+
}
774786
if self.subtype_of(l, &Type) && self.convert_tp_into_type(rhs.clone()).is_ok() {
775787
return true;
776788
}
@@ -937,6 +949,11 @@ impl Context {
937949
}
938950
}
939951

952+
/// ```erg
953+
/// Int.fields() == { imag: Int, real: Int, abs: (self: Int) -> Nat, ... }
954+
/// ?T(<: Int).fields() == Int.fields()
955+
/// Structural({ .x = Int }).fields() == { x: Int }
956+
/// ```
940957
pub fn fields(&self, t: &Type) -> Dict<Field, Type> {
941958
match t {
942959
Type::FreeVar(fv) if fv.is_linked() => self.fields(&fv.unwrap_linked()),

crates/erg_compiler/context/eval.rs

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2939,6 +2939,34 @@ impl Context {
29392939
}
29402940
Type::Quantified(quant) => self.convert_singular_type_into_value(*quant),
29412941
Type::Subr(subr) => self.convert_singular_type_into_value(*subr.return_t),
2942+
Type::Proj { lhs, rhs } => {
2943+
let old = lhs.clone().proj(rhs.clone());
2944+
let evaled = self.eval_proj(*lhs, rhs, 0, &()).map_err(|_| old.clone())?;
2945+
if old != evaled {
2946+
self.convert_singular_type_into_value(evaled)
2947+
} else {
2948+
Err(old)
2949+
}
2950+
}
2951+
Type::ProjCall {
2952+
lhs,
2953+
attr_name,
2954+
args,
2955+
} => {
2956+
let old = Type::ProjCall {
2957+
lhs: lhs.clone(),
2958+
attr_name: attr_name.clone(),
2959+
args: args.clone(),
2960+
};
2961+
let evaled = self
2962+
.eval_proj_call_t(*lhs, attr_name, args, 0, &())
2963+
.map_err(|_| old.clone())?;
2964+
if old != evaled {
2965+
self.convert_singular_type_into_value(evaled)
2966+
} else {
2967+
Err(old)
2968+
}
2969+
}
29422970
Type::Failure => Ok(ValueObj::Failure),
29432971
_ => Err(typ),
29442972
}
@@ -2993,7 +3021,15 @@ impl Context {
29933021
let end = fields["end"].clone();
29943022
Ok(closed_range(start.class(), start, end))
29953023
}
2996-
other => Err(other),
3024+
// TODO:
3025+
ValueObj::DataClass { .. }
3026+
| ValueObj::Int(_)
3027+
| ValueObj::Nat(_)
3028+
| ValueObj::Bool(_)
3029+
| ValueObj::Float(_)
3030+
| ValueObj::Code(_)
3031+
| ValueObj::Str(_)
3032+
| ValueObj::None => Err(val),
29973033
}
29983034
}
29993035

@@ -3083,7 +3119,8 @@ impl Context {
30833119
})
30843120
}
30853121
ValueObj::Failure => Ok(TyParam::Failure),
3086-
_ => Err(TyParam::Value(value)),
3122+
ValueObj::Subr(_) => Err(TyParam::Value(value)),
3123+
mono_value_pattern!(-Failure) => Err(TyParam::Value(value)),
30873124
}
30883125
}
30893126

@@ -3094,7 +3131,7 @@ impl Context {
30943131
self.convert_type_to_dict_type(t)
30953132
}
30963133
Type::Refinement(refine) => self.convert_type_to_dict_type(*refine.t),
3097-
Type::Poly { name, params } if &name[..] == "Dict" || &name[..] == "Dict!" => {
3134+
Type::Poly { params, .. } if ty.is_dict() || ty.is_dict_mut() => {
30983135
let dict = Dict::try_from(params[0].clone())?;
30993136
let mut new_dict = dict! {};
31003137
for (k, v) in dict.into_iter() {

crates/erg_compiler/context/generalize.rs

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use crate::ty::constructors::*;
1414
use crate::ty::free::{CanbeFree, Constraint, Free, HasLevel};
1515
use crate::ty::typaram::{TyParam, TyParamLambda};
1616
use crate::ty::value::ValueObj;
17-
use crate::ty::{HasType, Predicate, SubrType, Type};
17+
use crate::ty::{HasType, Predicate, SharedFrees, SubrType, Type};
1818

1919
use crate::context::{Context, Variance};
2020
use crate::error::{TyCheckError, TyCheckErrors, TyCheckResult};
@@ -45,10 +45,12 @@ impl<'c> Generalizer<'c> {
4545
fn generalize_tp(&mut self, free: TyParam, uninit: bool) -> TyParam {
4646
match free {
4747
TyParam::Type(t) => TyParam::t(self.generalize_t(*t, uninit)),
48-
TyParam::Value(val) => TyParam::Value(
49-
val.map_t(&mut |t| self.generalize_t(t, uninit))
50-
.map_tp(&mut |tp| self.generalize_tp(tp, uninit)),
51-
),
48+
TyParam::Value(val) => {
49+
TyParam::Value(val.map_t(&mut |t| self.generalize_t(t, uninit)).map_tp(
50+
&mut |tp| self.generalize_tp(tp, uninit),
51+
&SharedFrees::new(),
52+
))
53+
}
5254
TyParam::FreeVar(fv) if fv.is_generalized() => TyParam::FreeVar(fv),
5355
TyParam::FreeVar(fv) if fv.is_linked() => {
5456
let tp = fv.crack().clone();
@@ -200,13 +202,17 @@ impl<'c> Generalizer<'c> {
200202
// |T :> Int| X -> T ==> X -> Int
201203
self.generalize_t(sub, uninit)
202204
} else {
203-
fv.update_constraint(self.generalize_constraint(&fv), true);
204-
Type::FreeVar(fv)
205+
let constr = self.generalize_constraint(&fv);
206+
let ty = Type::FreeVar(fv);
207+
ty.update_constraint(constr, None, true);
208+
ty
205209
}
206210
} else {
207211
// ?S(: Str) => 'S
208-
fv.update_constraint(self.generalize_constraint(&fv), true);
209-
Type::FreeVar(fv)
212+
let constr = self.generalize_constraint(&fv);
213+
let ty = Type::FreeVar(fv);
214+
ty.update_constraint(constr, None, true);
215+
ty
210216
}
211217
}
212218
FreeVar(_) => free_type,
@@ -951,8 +957,9 @@ impl<'c, 'q, 'l, L: Locational> Dereferencer<'c, 'q, 'l, L> {
951957
} else {
952958
let new_constraint = fv.crack_constraint().clone();
953959
let new_constraint = self.deref_constraint(new_constraint)?;
954-
fv.update_constraint(new_constraint, true);
955-
Ok(Type::FreeVar(fv))
960+
let ty = Type::FreeVar(fv);
961+
ty.update_constraint(new_constraint, None, true);
962+
Ok(ty)
956963
}
957964
}
958965
FreeVar(_) => Ok(t),

0 commit comments

Comments
 (0)