Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

support transient inference contexts in the SLG solver #97

Merged
merged 11 commits into from Mar 19, 2018
Prev

pointless micro-optimization: clone instead of substitute

When we create a fresh inference context, we always map all free
variables to themselves, so we don't need to substitute.
  • Loading branch information...
nikomatsakis committed Mar 16, 2018
commit 86ca8b05d88e3cb7e5dcf8c8f12d8c78d845e040
Copy path View file
@@ -686,21 +686,6 @@ impl<T> Canonical<T> {
infer.rollback_to(snapshot);
result.quantified
}

/// Substitutes the values from `subst` in place of the values
/// bound by the binders in this canonical; the substitution should be
/// complete.
crate fn substitute(&self, mut subst: &Substitution) -> T::Result
where
T: Fold,
{
assert_eq!(
subst.parameters.len(),
self.binders.len(),
"substitute invoked with incomplete substitution",
);
self.value.fold_with(&mut subst, 0).unwrap()
}
}

/// A "universe canonical" value. This is a wrapper around a
@@ -719,18 +704,7 @@ impl<T> UCanonical<T> {
crate fn is_trivial_substitution(&self, canonical_subst: &Canonical<ConstrainedSubst>) -> bool {
let subst = &canonical_subst.value.subst;
assert_eq!(self.canonical.binders.len(), subst.parameters.len());
// A subst is trivial if..
subst.parameters.iter().zip(0..).all(|(parameter, index)| {
// All types and lifetimes are mapped to distinct
// variables. Since this has been canonicalized, and
// the substitution appears first, those will also be
// the first N variables.
match parameter {
ParameterKind::Ty(Ty::Var(depth)) => index == *depth,
ParameterKind::Lifetime(Lifetime::Var(depth)) => index == *depth,
_ => false,
}
})
subst.is_identity_subst()
}
}

@@ -884,6 +858,28 @@ impl Substitution {
crate fn is_empty(&self) -> bool {
self.parameters.is_empty()
}

/// A substitution is an **identity substitution** if it looks
/// like this
///
/// ```text
/// ?0 := ?0
/// ?1 := ?1
/// ?2 := ?2
/// ...
/// ```
///
/// Basically, each value is mapped to a type or lifetime with its
/// same index.
crate fn is_identity_subst(&self) -> bool {
self.parameters.iter().zip(0..).all(|(parameter, index)| {
match parameter {
ParameterKind::Ty(Ty::Var(depth)) => index == *depth,
ParameterKind::Lifetime(Lifetime::Var(depth)) => index == *depth,
_ => false,
}
})
}
}

impl<'a> DefaultTypeFolder for &'a Substitution {}
Copy path View file
@@ -51,9 +51,9 @@ impl InferenceTable {
crate fn from_canonical<T>(
num_universes: usize,
canonical: &Canonical<T>,
) -> (Self, Substitution, T::Result)
) -> (Self, Substitution, T)
where
T: Fold,
T: Fold<Result = T> + Clone,
{
let mut table = InferenceTable::new();

@@ -63,7 +63,21 @@ impl InferenceTable {
}

let subst = table.fresh_subst(&canonical.binders);
let value = canonical.substitute(&subst);

// Pointless micro-optimization: The fully correct way to
// instantiate `value` is to substitute `subst` like so:
//
// let value = canonical.substitute(&subst);
//
// However, because (a) this is a canonical value, and hence
// contains no free variables except for those bound in the
// canonical binders and (b) we just create the inference
// table, and we created all of its variables from those same
// binders, we know that this substitution will have the form
// `?0 := ?0` and so forth. So we can just "clone" the
// canonical value rather than actually substituting.
assert!(subst.is_identity_subst());
let value = canonical.value.clone();

(table, subst, value)
}
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.