remove type variable defaults code
This just limits ourselves to the "old school" defaults: diverging variables and integer variables.
This commit is contained in:
parent
c58c928e65
commit
4a0a0e949a
@ -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");
|
||||
|
||||
|
@ -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
|
||||
}
|
@ -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
|
||||
}
|
@ -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();
|
||||
}
|
@ -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 };
|
||||
}
|
@ -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);
|
||||
}
|
@ -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();
|
||||
}
|
@ -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);
|
||||
}
|
@ -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
|
||||
}
|
@ -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
|
||||
}
|
@ -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();
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user