remove type variable defaults code

This just limits ourselves to the "old school" defaults: diverging
variables and integer variables.
This commit is contained in:
Niko Matsakis 2017-03-09 21:29:22 -05:00
parent c58c928e65
commit 4a0a0e949a
11 changed files with 3 additions and 485 deletions

View File

@ -88,7 +88,7 @@ use hir::def::{Def, CtorKind};
use hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
use rustc_back::slice::ref_slice;
use rustc::infer::{self, InferCtxt, InferOk, RegionVariableOrigin};
use rustc::infer::type_variable::{self, TypeVariableOrigin};
use rustc::infer::type_variable::{TypeVariableOrigin};
use rustc::ty::subst::{Kind, Subst, Substs};
use rustc::traits::{self, ObligationCause, ObligationCauseCode, Reveal};
use rustc::ty::{ParamTy, ParameterEnvironment};
@ -105,7 +105,7 @@ use session::{Session, CompileResult};
use TypeAndSubsts;
use lint;
use util::common::{ErrorReported, indenter};
use util::nodemap::{DefIdMap, FxHashMap, FxHashSet, NodeMap};
use util::nodemap::{DefIdMap, FxHashMap, NodeMap};
use std::cell::{Cell, RefCell};
use std::cmp;
@ -1978,218 +1978,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
}
}
// Implements type inference fallback algorithm
fn select_all_obligations_and_apply_defaults(&self) {
if self.tcx.sess.features.borrow().default_type_parameter_fallback {
self.new_select_all_obligations_and_apply_defaults();
} else {
self.old_select_all_obligations_and_apply_defaults();
}
}
// Implements old type inference fallback algorithm
fn old_select_all_obligations_and_apply_defaults(&self) {
self.select_obligations_where_possible();
self.default_type_parameters();
self.select_obligations_where_possible();
}
fn new_select_all_obligations_and_apply_defaults(&self) {
use rustc::ty::error::UnconstrainedNumeric::Neither;
use rustc::ty::error::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat};
// For the time being this errs on the side of being memory wasteful but provides better
// error reporting.
// let type_variables = self.type_variables.clone();
// There is a possibility that this algorithm will have to run an arbitrary number of times
// to terminate so we bound it by the compiler's recursion limit.
for _ in 0..self.tcx.sess.recursion_limit.get() {
// First we try to solve all obligations, it is possible that the last iteration
// has made it possible to make more progress.
self.select_obligations_where_possible();
let mut conflicts = Vec::new();
// Collect all unsolved type, integral and floating point variables.
let unsolved_variables = self.unsolved_variables();
// We must collect the defaults *before* we do any unification. Because we have
// directly attached defaults to the type variables any unification that occurs
// will erase defaults causing conflicting defaults to be completely ignored.
let default_map: FxHashMap<Ty<'tcx>, _> =
unsolved_variables
.iter()
.filter_map(|t| self.default(t).map(|d| (*t, d)))
.collect();
let mut unbound_tyvars = FxHashSet();
debug!("select_all_obligations_and_apply_defaults: defaults={:?}", default_map);
// We loop over the unsolved variables, resolving them and if they are
// and unconstrainted numeric type we add them to the set of unbound
// variables. We do this so we only apply literal fallback to type
// variables without defaults.
for ty in &unsolved_variables {
let resolved = self.resolve_type_vars_if_possible(ty);
if self.type_var_diverges(resolved) {
self.demand_eqtype(syntax_pos::DUMMY_SP, *ty,
self.tcx.mk_diverging_default());
} else {
match self.type_is_unconstrained_numeric(resolved) {
UnconstrainedInt | UnconstrainedFloat => {
unbound_tyvars.insert(resolved);
},
Neither => {}
}
}
}
// We now remove any numeric types that also have defaults, and instead insert
// the type variable with a defined fallback.
for ty in &unsolved_variables {
if let Some(_default) = default_map.get(ty) {
let resolved = self.resolve_type_vars_if_possible(ty);
debug!("select_all_obligations_and_apply_defaults: \
ty: {:?} with default: {:?}",
ty, _default);
match resolved.sty {
ty::TyInfer(ty::TyVar(_)) => {
unbound_tyvars.insert(ty);
}
ty::TyInfer(ty::IntVar(_)) | ty::TyInfer(ty::FloatVar(_)) => {
unbound_tyvars.insert(ty);
if unbound_tyvars.contains(resolved) {
unbound_tyvars.remove(resolved);
}
}
_ => {}
}
}
}
// If there are no more fallbacks to apply at this point we have applied all possible
// defaults and type inference will proceed as normal.
if unbound_tyvars.is_empty() {
break;
}
// Finally we go through each of the unbound type variables and unify them with
// the proper fallback, reporting a conflicting default error if any of the
// unifications fail. We know it must be a conflicting default because the
// variable would only be in `unbound_tyvars` and have a concrete value if
// it had been solved by previously applying a default.
// We wrap this in a transaction for error reporting, if we detect a conflict
// we will rollback the inference context to its prior state so we can probe
// for conflicts and correctly report them.
let _ = self.commit_if_ok(|_: &infer::CombinedSnapshot| {
conflicts.extend(
self.apply_defaults_and_return_conflicts(&unbound_tyvars, &default_map, None)
);
// If there are conflicts we rollback, otherwise commit
if conflicts.len() > 0 {
Err(())
} else {
Ok(())
}
});
// Loop through each conflicting default, figuring out the default that caused
// a unification failure and then report an error for each.
for (conflict, default) in conflicts {
let conflicting_default =
self.apply_defaults_and_return_conflicts(
&unbound_tyvars,
&default_map,
Some(conflict)
)
.last()
.map(|(_, tv)| tv)
.unwrap_or(type_variable::Default {
ty: self.next_ty_var(
TypeVariableOrigin::MiscVariable(syntax_pos::DUMMY_SP)),
origin_span: syntax_pos::DUMMY_SP,
// what do I put here?
def_id: self.tcx.hir.local_def_id(ast::CRATE_NODE_ID)
});
// This is to ensure that we elimnate any non-determinism from the error
// reporting by fixing an order, it doesn't matter what order we choose
// just that it is consistent.
let (first_default, second_default) =
if default.def_id < conflicting_default.def_id {
(default, conflicting_default)
} else {
(conflicting_default, default)
};
self.report_conflicting_default_types(
first_default.origin_span,
self.body_id,
first_default,
second_default)
}
}
self.select_obligations_where_possible();
}
// For use in error handling related to default type parameter fallback. We explicitly
// apply the default that caused conflict first to a local version of the type variable
// table then apply defaults until we find a conflict. That default must be the one
// that caused conflict earlier.
fn apply_defaults_and_return_conflicts<'b>(
&'b self,
unbound_vars: &'b FxHashSet<Ty<'tcx>>,
default_map: &'b FxHashMap<Ty<'tcx>, type_variable::Default<'tcx>>,
conflict: Option<Ty<'tcx>>,
) -> impl Iterator<Item=(Ty<'tcx>, type_variable::Default<'tcx>)> + 'b {
use rustc::ty::error::UnconstrainedNumeric::Neither;
use rustc::ty::error::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat};
conflict.into_iter().chain(unbound_vars.iter().cloned()).flat_map(move |ty| {
if self.type_var_diverges(ty) {
self.demand_eqtype(syntax_pos::DUMMY_SP, ty,
self.tcx.mk_diverging_default());
} else {
match self.type_is_unconstrained_numeric(ty) {
UnconstrainedInt => {
self.demand_eqtype(syntax_pos::DUMMY_SP, ty, self.tcx.types.i32)
},
UnconstrainedFloat => {
self.demand_eqtype(syntax_pos::DUMMY_SP, ty, self.tcx.types.f64)
},
Neither => {
if let Some(default) = default_map.get(ty) {
let default = default.clone();
let default_ty = self.normalize_associated_types_in(
default.origin_span, &default.ty);
match self.eq_types(false,
&self.misc(default.origin_span),
ty,
default_ty) {
Ok(ok) => self.register_infer_ok_obligations(ok),
Err(_) => {
return Some((ty, default));
}
}
}
}
}
}
None
})
}
fn select_all_obligations_or_error(&self) {
debug!("select_all_obligations_or_error");

View File

@ -1,33 +0,0 @@
// Copyright 2015 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.
#![feature(default_type_parameter_fallback)]
use std::fmt::Debug;
// Example from the RFC
fn foo<F:Default=usize>() -> F { F::default() }
//~^ NOTE: a default was defined here...
fn bar<B:Debug=isize>(b: B) { println!("{:?}", b); }
//~^ NOTE: a second default was defined here...
fn main() {
// Here, F is instantiated with $0=uint
let x = foo();
//~^ ERROR: mismatched types
//~| NOTE: conflicting type parameter defaults `usize` and `isize`
//~| NOTE: conflicting type parameter defaults `usize` and `isize`
//~| NOTE: ...that was applied to an unconstrained type variable here
// Here, B is instantiated with $1=uint, and constraint $0 <: $1 is added.
bar(x);
//~^ NOTE: ...that also applies to the same type variable here
}

View File

@ -1,32 +0,0 @@
// Copyright 2015 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.
//
//aux-build:default_ty_param_cross_crate_crate.rs
#![feature(default_type_parameter_fallback)]
extern crate default_param_test;
use default_param_test::{Foo, bleh};
fn meh<X, B=bool>(x: Foo<X, B>) {}
//~^ NOTE: a default was defined here...
fn main() {
let foo = bleh();
//~^ NOTE: ...that also applies to the same type variable here
meh(foo);
//~^ ERROR: mismatched types
//~| NOTE: conflicting type parameter defaults `bool` and `char`
//~| NOTE: conflicting type parameter defaults `bool` and `char`
//~| a second default is defined on `default_param_test::bleh`
//~| NOTE: ...that was applied to an unconstrained type variable here
}

View File

@ -1,36 +0,0 @@
// Copyright 2015 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.
//
#![feature(default_type_parameter_fallback)]
use std::marker::PhantomData;
trait Id {
type This;
}
impl<A> Id for A {
type This = A;
}
struct Foo<X: Default = usize, Y = <X as Id>::This> {
data: PhantomData<(X, Y)>
}
impl<X: Default, Y> Foo<X, Y> {
fn new() -> Foo<X, Y> {
Foo { data: PhantomData }
}
}
fn main() {
let foo = Foo::new();
}

View File

@ -1,19 +0,0 @@
// Copyright 2015 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.
//
#![feature(default_type_parameter_fallback)]
use std::marker::PhantomData;
struct Foo<T,U=T> { t: T, data: PhantomData<U> }
fn main() {
let foo = Foo { t: 'a', data: PhantomData };
}

View File

@ -1,24 +0,0 @@
// Copyright 2015 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.
#![feature(default_type_parameter_fallback)]
struct Foo;
impl Foo {
fn method<A:Default=String>(&self) -> A {
A::default()
}
}
fn main() {
let f = Foo.method();
println!("{}", f);
}

View File

@ -1,23 +0,0 @@
// Copyright 2015 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.
#![feature(default_type_parameter_fallback)]
struct Foo<A>(A);
impl<A:Default=i32> Foo<A> {
fn new() -> Foo<A> {
Foo(A::default())
}
}
fn main() {
let foo = Foo::new();
}

View File

@ -1,40 +0,0 @@
// Copyright 2015 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.
//
#![feature(default_type_parameter_fallback)]
use std::marker::PhantomData;
pub struct DeterministicHasher;
pub struct RandomHasher;
pub struct MyHashMap<K, V, H=DeterministicHasher> {
data: PhantomData<(K, V, H)>
}
impl<K, V, H> MyHashMap<K, V, H> {
fn new() -> MyHashMap<K, V, H> {
MyHashMap { data: PhantomData }
}
}
mod mystd {
use super::{MyHashMap, RandomHasher};
pub type HashMap<K, V, H=RandomHasher> = MyHashMap<K, V, H>;
}
fn try_me<H>(hash_map: mystd::HashMap<i32, i32, H>) {}
fn main() {
let hash_map = mystd::HashMap::new();
try_me(hash_map);
}

View File

@ -1,25 +0,0 @@
// Copyright 2015 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.
#![feature(default_type_parameter_fallback)]
// Another example from the RFC
trait Foo { }
trait Bar { }
impl<T:Bar=usize> Foo for Vec<T> {}
impl Bar for usize {}
fn takes_foo<F:Foo>(f: F) {}
fn main() {
let x = Vec::new(); // x: Vec<$0>
takes_foo(x); // adds oblig Vec<$0> : Foo
}

View File

@ -1,26 +0,0 @@
// Copyright 2015 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.
#![feature(default_type_parameter_fallback)]
// An example from the RFC
trait Foo { fn takes_foo(&self); }
trait Bar { }
impl<T:Bar=usize> Foo for Vec<T> {
fn takes_foo(&self) {}
}
impl Bar for usize {}
fn main() {
let x = Vec::new(); // x: Vec<$0>
x.takes_foo(); // adds oblig Vec<$0> : Foo
}

View File

@ -1,19 +0,0 @@
// Copyright 2015 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.
#![feature(default_type_parameter_fallback)]
use std::collections::HashMap;
type IntMap<K=usize> = HashMap<K, usize>;
fn main() {
let x = IntMap::new();
}