use traits::ObligationCause;
use ty::{self, Ty, TyCtxt};
+use ty::error::TypeError;
use ty::relate::{Relate, RelateResult, TypeRelation};
/// "Greatest lower bound" (common subtype)
-> RelateResult<'tcx, ty::Binder<T>>
where T: Relate<'tcx>
{
- self.fields.higher_ranked_glb(a, b, self.a_is_expected)
+ let was_error = self.infcx().probe(|_snapshot| {
+ // Subtle: use a fresh combine-fields here because we recover
+ // from Err. Doing otherwise could propagate obligations out
+ // through our `self.obligations` field.
+ self.infcx()
+ .combine_fields(self.fields.trace.clone(), self.fields.param_env)
+ .higher_ranked_glb(a, b, self.a_is_expected)
+ .is_err()
+ });
+
+ // When higher-ranked types are involved, computing the LUB is
+ // very challenging, switch to invariance. This is obviously
+ // overly conservative but works ok in practice.
+ match self.relate_with_variance(ty::Variance::Invariant, a, b) {
+ Ok(_) => Ok(a.clone()),
+ Err(err) => {
+ if !was_error {
+ Err(TypeError::OldStyleLUB(Box::new(err)))
+ } else {
+ Err(err)
+ }
+ }
+ }
}
}
use traits::ObligationCause;
use ty::{self, Ty, TyCtxt};
+use ty::error::TypeError;
use ty::relate::{Relate, RelateResult, TypeRelation};
/// "Least upper bound" (common supertype)
-> RelateResult<'tcx, ty::Binder<T>>
where T: Relate<'tcx>
{
- self.fields.higher_ranked_lub(a, b, self.a_is_expected)
+ let was_error = self.infcx().probe(|_snapshot| {
+ // Subtle: use a fresh combine-fields here because we recover
+ // from Err. Doing otherwise could propagate obligations out
+ // through our `self.obligations` field.
+ self.infcx()
+ .combine_fields(self.fields.trace.clone(), self.fields.param_env)
+ .higher_ranked_lub(a, b, self.a_is_expected)
+ .is_err()
+ });
+
+ // When higher-ranked types are involved, computing the LUB is
+ // very challenging, switch to invariance. This is obviously
+ // overly conservative but works ok in practice.
+ match self.relate_with_variance(ty::Variance::Invariant, a, b) {
+ Ok(_) => Ok(a.clone()),
+ Err(err) => {
+ if !was_error {
+ Err(TypeError::OldStyleLUB(Box::new(err)))
+ } else {
+ Err(err)
+ }
+ }
+ }
}
}
ProjectionBoundsLength(ExpectedFound<usize>),
TyParamDefaultMismatch(ExpectedFound<type_variable::Default<'tcx>>),
ExistentialMismatch(ExpectedFound<&'tcx ty::Slice<ty::ExistentialPredicate<'tcx>>>),
+
+ OldStyleLUB(Box<TypeError<'tcx>>),
}
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Debug, Copy)]
report_maybe_different(f, format!("trait `{}`", values.expected),
format!("trait `{}`", values.found))
}
+ OldStyleLUB(ref err) => {
+ write!(f, "{}", err)
+ }
}
}
}
TyParamDefaultMismatch(ref x) => {
return tcx.lift(x).map(TyParamDefaultMismatch)
}
- ExistentialMismatch(ref x) => return tcx.lift(x).map(ExistentialMismatch)
+ ExistentialMismatch(ref x) => return tcx.lift(x).map(ExistentialMismatch),
+ OldStyleLUB(ref x) => return tcx.lift(x).map(OldStyleLUB),
})
}
}
Sorts(x) => Sorts(x.fold_with(folder)),
TyParamDefaultMismatch(ref x) => TyParamDefaultMismatch(x.fold_with(folder)),
ExistentialMismatch(x) => ExistentialMismatch(x.fold_with(folder)),
+ OldStyleLUB(ref x) => OldStyleLUB(x.fold_with(folder)),
}
}
b.visit_with(visitor)
},
Sorts(x) => x.visit_with(visitor),
+ OldStyleLUB(ref x) => x.visit_with(visitor),
TyParamDefaultMismatch(ref x) => x.visit_with(visitor),
ExistentialMismatch(x) => x.visit_with(visitor),
Mismatch |
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test for a specific corner case: when we compute the LUB of two fn
+// types and their parameters have unbound variables. In that case, we
+// wind up relating those two variables. This was causing an ICE in an
+// in-progress PR.
+
+fn main() {
+ let a_f: fn(_) = |_| ();
+ let b_f: fn(_) = |_| ();
+ let c_f = match 22 {
+ 0 => a_f,
+ _ => b_f,
+ };
+ c_f(4);
+}