Implement Default TyParam fallback
This patch allows type parameter defaults to influence type inference. This is a possible breaking change since it effects the way type inference works and will have different behavior when mixing defaults and literal fallback.
This commit is contained in:
parent
7276d8b761
commit
bbcb13da88
@ -95,6 +95,9 @@ pub struct InferCtxt<'a, 'tcx: 'a> {
|
||||
normalize: bool,
|
||||
|
||||
err_count_on_creation: usize,
|
||||
|
||||
// Default Type Parameter fallbacks
|
||||
pub defaults: RefCell<FnvHashMap<Ty<'tcx>, Ty<'tcx>>>,
|
||||
}
|
||||
|
||||
/// A map returned by `skolemize_late_bound_regions()` indicating the skolemized
|
||||
@ -350,7 +353,8 @@ pub fn new_infer_ctxt<'a, 'tcx>(tcx: &'a ty::ctxt<'tcx>,
|
||||
parameter_environment: param_env.unwrap_or(tcx.empty_parameter_environment()),
|
||||
fulfillment_cx: RefCell::new(traits::FulfillmentContext::new(errors_will_be_reported)),
|
||||
normalize: false,
|
||||
err_count_on_creation: tcx.sess.err_count()
|
||||
err_count_on_creation: tcx.sess.err_count(),
|
||||
defaults: RefCell::new(FnvHashMap()),
|
||||
}
|
||||
}
|
||||
|
||||
@ -653,6 +657,30 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn unsolved_variables(&self) -> Vec<ty::Ty<'tcx>> {
|
||||
let mut variables = Vec::new();
|
||||
|
||||
let unbound_ty_vars = self.type_variables
|
||||
.borrow()
|
||||
.unsolved_variables()
|
||||
.into_iter().map(|t| self.tcx.mk_var(t));
|
||||
|
||||
let unbound_int_vars = self.int_unification_table
|
||||
.borrow_mut()
|
||||
.unsolved_variables()
|
||||
.into_iter().map(|v| self.tcx.mk_int_var(v));
|
||||
|
||||
let unbound_float_vars = self.float_unification_table
|
||||
.borrow_mut()
|
||||
.unsolved_variables()
|
||||
.into_iter().map(|v| self.tcx.mk_float_var(v));
|
||||
|
||||
variables.extend(unbound_ty_vars);
|
||||
variables.extend(unbound_int_vars);
|
||||
variables.extend(unbound_float_vars);
|
||||
return variables;
|
||||
}
|
||||
|
||||
fn combine_fields(&'a self, a_is_expected: bool, trace: TypeTrace<'tcx>)
|
||||
-> CombineFields<'a, 'tcx> {
|
||||
CombineFields {infcx: self,
|
||||
@ -996,6 +1024,23 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn type_vars_for_defs(&self,
|
||||
defs: &[ty::TypeParameterDef<'tcx>])
|
||||
-> Vec<ty::Ty<'tcx>> {
|
||||
let mut vars = Vec::with_capacity(defs.len());
|
||||
|
||||
for def in defs.iter() {
|
||||
let ty_var = self.next_ty_var();
|
||||
match def.default {
|
||||
None => {},
|
||||
Some(default) => { self.defaults.borrow_mut().insert(ty_var, default); }
|
||||
}
|
||||
vars.push(ty_var)
|
||||
}
|
||||
|
||||
vars
|
||||
}
|
||||
|
||||
/// Given a set of generics defined on a type or impl, returns a substitution mapping each
|
||||
/// type/region parameter to a fresh inference variable.
|
||||
pub fn fresh_substs_for_generics(&self,
|
||||
@ -1003,9 +1048,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
generics: &ty::Generics<'tcx>)
|
||||
-> subst::Substs<'tcx>
|
||||
{
|
||||
let type_params =
|
||||
generics.types.map(
|
||||
|_| self.next_ty_var());
|
||||
let mut type_params = subst::VecPerParamSpace::empty();
|
||||
|
||||
for space in subst::ParamSpace::all().iter() {
|
||||
type_params.replace(*space, self.type_vars_for_defs(generics.types.get_slice(*space)))
|
||||
}
|
||||
|
||||
let region_params =
|
||||
generics.regions.map(
|
||||
|d| self.next_region_var(EarlyBoundRegion(span, d.name)));
|
||||
@ -1027,8 +1075,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
assert!(generics.regions.len(subst::SelfSpace) == 0);
|
||||
assert!(generics.regions.len(subst::FnSpace) == 0);
|
||||
|
||||
let type_parameter_count = generics.types.len(subst::TypeSpace);
|
||||
let type_parameters = self.next_ty_vars(type_parameter_count);
|
||||
let type_parameter_defs = generics.types.get_slice(subst::TypeSpace);
|
||||
let type_parameters = self.type_vars_for_defs(type_parameter_defs);
|
||||
|
||||
let region_param_defs = generics.regions.get_slice(subst::TypeSpace);
|
||||
let regions = self.region_vars_for_defs(span, region_param_defs);
|
||||
@ -1268,6 +1316,24 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
self.report_and_explain_type_error(trace, err);
|
||||
}
|
||||
|
||||
pub fn report_conflicting_default_types(&self,
|
||||
span: Span,
|
||||
expected: Ty<'tcx>,
|
||||
actual: Ty<'tcx>) {
|
||||
let trace = TypeTrace {
|
||||
origin: Misc(span),
|
||||
values: Types(ty::expected_found {
|
||||
expected: expected,
|
||||
found: actual
|
||||
})
|
||||
};
|
||||
|
||||
self.report_and_explain_type_error(trace, &ty::type_err::terr_ty_param_default_mismatch(ty::expected_found {
|
||||
expected: expected,
|
||||
found: actual
|
||||
}));
|
||||
}
|
||||
|
||||
pub fn replace_late_bound_regions_with_fresh_var<T>(
|
||||
&self,
|
||||
span: Span,
|
||||
|
@ -195,6 +195,15 @@ impl<'tcx> TypeVariableTable<'tcx> {
|
||||
|
||||
escaping_types
|
||||
}
|
||||
|
||||
pub fn unsolved_variables(&self) -> Vec<ty::TyVid> {
|
||||
self.values.iter().enumerate().filter_map(|(i, value)|
|
||||
match &value.value {
|
||||
&TypeVariableValue::Known(_) => None,
|
||||
&TypeVariableValue::Bounded(_) => Some(ty::TyVid { index: i as u32 })
|
||||
}
|
||||
).collect()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> sv::SnapshotVecDelegate for Delegate<'tcx> {
|
||||
|
@ -2068,6 +2068,7 @@ pub enum TypeError<'tcx> {
|
||||
ConvergenceMismatch(ExpectedFound<bool>),
|
||||
ProjectionNameMismatched(ExpectedFound<ast::Name>),
|
||||
ProjectionBoundsLength(ExpectedFound<usize>),
|
||||
terr_ty_param_default_mismatch(expected_found<Ty<'tcx>>)
|
||||
}
|
||||
|
||||
/// Bounds suitable for an existentially quantified type parameter
|
||||
@ -5080,6 +5081,11 @@ impl<'tcx> fmt::Display for TypeError<'tcx> {
|
||||
write!(f, "expected {} associated type bindings, found {}",
|
||||
values.expected,
|
||||
values.found)
|
||||
},
|
||||
terr_ty_param_default_mismatch(ref values) => {
|
||||
write!(f, "conflicting type parameter defaults {} {}",
|
||||
values.expected,
|
||||
values.found)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -5437,6 +5443,11 @@ impl<'tcx> ctxt<'tcx> {
|
||||
&format!("consider boxing your closure and/or \
|
||||
using it as a trait object"));
|
||||
}
|
||||
},
|
||||
terr_ty_param_default_mismatch(expected) => {
|
||||
self.sess.span_note(sp,
|
||||
&format!("found conflicting defaults {:?} {:?}",
|
||||
expected.expected, expected.found))
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
@ -339,5 +339,11 @@ impl<'tcx,K,V> UnificationTable<K>
|
||||
pub fn probe(&mut self, a_id: K) -> Option<V> {
|
||||
self.get(a_id).value.clone()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn unsolved_variables(&mut self) -> Vec<K> {
|
||||
self.values
|
||||
.iter()
|
||||
.filter_map(|vv| if vv.value.is_some() { None } else { Some(vv.key()) })
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
@ -309,15 +309,17 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
|
||||
// If they were not explicitly supplied, just construct fresh
|
||||
// variables.
|
||||
let num_supplied_types = supplied_method_types.len();
|
||||
let num_method_types = pick.item.as_opt_method().unwrap()
|
||||
.generics.types.len(subst::FnSpace);
|
||||
let method = pick.item.as_opt_method().unwrap();
|
||||
let method_types = method.generics.types.get_slice(subst::FnSpace);
|
||||
let num_method_types = method_types.len();
|
||||
|
||||
let method_types = {
|
||||
if num_supplied_types == 0 {
|
||||
self.fcx.infcx().next_ty_vars(num_method_types)
|
||||
self.fcx.infcx().type_vars_for_defs(method_types)
|
||||
} else if num_method_types == 0 {
|
||||
span_err!(self.tcx().sess, self.span, E0035,
|
||||
"does not take type parameters");
|
||||
self.fcx.infcx().next_ty_vars(num_method_types)
|
||||
self.fcx.infcx().type_vars_for_defs(method_types)
|
||||
} else if num_supplied_types != num_method_types {
|
||||
span_err!(self.tcx().sess, self.span, E0036,
|
||||
"incorrect number of type parameters given for this method");
|
||||
|
@ -167,7 +167,8 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
||||
|
||||
let trait_def = fcx.tcx().lookup_trait_def(trait_def_id);
|
||||
|
||||
let expected_number_of_input_types = trait_def.generics.types.len(subst::TypeSpace);
|
||||
let type_parameter_defs = trait_def.generics.types.get_slice(subst::TypeSpace);
|
||||
let expected_number_of_input_types = type_parameter_defs.len();
|
||||
let input_types = match opt_input_types {
|
||||
Some(input_types) => {
|
||||
assert_eq!(expected_number_of_input_types, input_types.len());
|
||||
@ -175,7 +176,7 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
||||
}
|
||||
|
||||
None => {
|
||||
fcx.inh.infcx.next_ty_vars(expected_number_of_input_types)
|
||||
fcx.inh.infcx.type_vars_for_defs(type_parameter_defs)
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1207,8 +1207,8 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
|
||||
!method.generics.regions.is_empty_in(subst::FnSpace)
|
||||
{
|
||||
let method_types =
|
||||
self.infcx().next_ty_vars(
|
||||
method.generics.types.len(subst::FnSpace));
|
||||
self.infcx().type_vars_for_defs(
|
||||
method.generics.types.get_slice(subst::FnSpace));
|
||||
|
||||
// In general, during probe we erase regions. See
|
||||
// `impl_self_ty()` for an explanation.
|
||||
|
@ -108,6 +108,7 @@ use util::nodemap::{DefIdMap, FnvHashMap, NodeMap};
|
||||
use util::lev_distance::lev_distance;
|
||||
|
||||
use std::cell::{Cell, Ref, RefCell};
|
||||
use std::collections::HashSet;
|
||||
use std::mem::replace;
|
||||
use std::slice;
|
||||
use syntax::{self, abi, attr};
|
||||
@ -1255,28 +1256,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Apply "fallbacks" to some types
|
||||
/// ! gets replaced with (), unconstrained ints with i32, and unconstrained floats with f64.
|
||||
pub fn default_type_parameters(&self) {
|
||||
use middle::ty::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat, Neither};
|
||||
for (_, &mut ref ty) in &mut self.inh.tables.borrow_mut().node_types {
|
||||
let resolved = self.infcx().resolve_type_vars_if_possible(ty);
|
||||
if self.infcx().type_var_diverges(resolved) {
|
||||
demand::eqtype(self, codemap::DUMMY_SP, *ty, self.tcx().mk_nil());
|
||||
} else {
|
||||
match self.infcx().type_is_unconstrained_numeric(resolved) {
|
||||
UnconstrainedInt => {
|
||||
demand::eqtype(self, codemap::DUMMY_SP, *ty, self.tcx().types.i32)
|
||||
},
|
||||
UnconstrainedFloat => {
|
||||
demand::eqtype(self, codemap::DUMMY_SP, *ty, self.tcx().types.f64)
|
||||
}
|
||||
Neither => { }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn write_ty(&self, node_id: ast::NodeId, ty: Ty<'tcx>) {
|
||||
debug!("write_ty({}, {:?}) in fcx {}",
|
||||
@ -1711,11 +1690,98 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
}
|
||||
|
||||
fn select_all_obligations_and_apply_defaults(&self) {
|
||||
debug!("select_all_obligations_and_apply_defaults");
|
||||
use middle::ty::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat, Neither};
|
||||
|
||||
self.select_obligations_where_possible();
|
||||
self.default_type_parameters();
|
||||
self.select_obligations_where_possible();
|
||||
debug!("select_all_obligations_and_apply_defaults: defaults={:?}", self.infcx().defaults);
|
||||
|
||||
for _ in (0..self.tcx().sess.recursion_limit.get()) {
|
||||
self.select_obligations_where_possible();
|
||||
|
||||
let unsolved_variables = self.inh.infcx.unsolved_variables();
|
||||
let mut unbound_tyvars = HashSet::new();
|
||||
|
||||
// Gather all unconstrainted integer and float variables
|
||||
for ty in &unsolved_variables {
|
||||
let resolved = self.infcx().resolve_type_vars_if_possible(ty);
|
||||
if self.infcx().type_var_diverges(resolved) {
|
||||
demand::eqtype(self, codemap::DUMMY_SP, *ty, self.tcx().mk_nil());
|
||||
} else {
|
||||
match self.infcx().type_is_unconstrained_numeric(resolved) {
|
||||
UnconstrainedInt => {
|
||||
unbound_tyvars.insert(resolved);
|
||||
},
|
||||
UnconstrainedFloat => {
|
||||
unbound_tyvars.insert(resolved);
|
||||
}
|
||||
Neither => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Collect the set of variables that need fallback applied
|
||||
for ty in &unsolved_variables {
|
||||
if self.inh.infcx.defaults.borrow().contains_key(ty) {
|
||||
let resolved = self.infcx().resolve_type_vars_if_possible(ty);
|
||||
|
||||
debug!("select_all_obligations_and_apply_defaults: ty: {:?} with default: {:?}",
|
||||
ty, self.inh.infcx.defaults.borrow().get(ty));
|
||||
|
||||
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 unbound_tyvars.is_empty() {
|
||||
break;
|
||||
}
|
||||
|
||||
// Go through the unbound variables and unify them with the proper fallbacks
|
||||
for ty in &unbound_tyvars {
|
||||
// let resolved = self.infcx().resolve_type_vars_if_possible(ty);
|
||||
if self.infcx().type_var_diverges(ty) {
|
||||
demand::eqtype(self, codemap::DUMMY_SP, *ty, self.tcx().mk_nil());
|
||||
} else {
|
||||
match self.infcx().type_is_unconstrained_numeric(ty) {
|
||||
UnconstrainedInt => {
|
||||
demand::eqtype(self, codemap::DUMMY_SP, *ty, self.tcx().types.i32)
|
||||
},
|
||||
UnconstrainedFloat => {
|
||||
demand::eqtype(self, codemap::DUMMY_SP, *ty, self.tcx().types.f64)
|
||||
}
|
||||
Neither => {
|
||||
let default_map = self.inh.infcx.defaults.borrow();
|
||||
if let Some(default) = default_map.get(ty) {
|
||||
match infer::mk_eqty(self.infcx(), false,
|
||||
infer::Misc(codemap::DUMMY_SP),
|
||||
ty, default) {
|
||||
Ok(()) => { /* ok */ }
|
||||
Err(_) => {
|
||||
self.infcx().report_conflicting_default_types(
|
||||
codemap::DUMMY_SP,
|
||||
ty,
|
||||
default)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.select_obligations_where_possible();
|
||||
}
|
||||
}
|
||||
|
||||
fn select_all_obligations_or_error(&self) {
|
||||
@ -2421,13 +2487,15 @@ pub fn impl_self_ty<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
||||
let tcx = fcx.tcx();
|
||||
|
||||
let ity = tcx.lookup_item_type(did);
|
||||
let (n_tps, rps, raw_ty) =
|
||||
(ity.generics.types.len(subst::TypeSpace),
|
||||
let (tps, rps, raw_ty) =
|
||||
(ity.generics.types.get_slice(subst::TypeSpace),
|
||||
ity.generics.regions.get_slice(subst::TypeSpace),
|
||||
ity.ty);
|
||||
|
||||
debug!("impl_self_ty: tps={:?} rps={:?} raw_ty={:?}", tps, rps, raw_ty);
|
||||
|
||||
let rps = fcx.inh.infcx.region_vars_for_defs(span, rps);
|
||||
let tps = fcx.inh.infcx.next_ty_vars(n_tps);
|
||||
let tps = fcx.inh.infcx.type_vars_for_defs(tps);
|
||||
let substs = subst::Substs::new_type(tps, rps);
|
||||
let substd_ty = fcx.instantiate_type_scheme(span, &substs, &raw_ty);
|
||||
|
||||
@ -4647,7 +4715,7 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
||||
// Nothing specified at all: supply inference variables for
|
||||
// everything.
|
||||
if provided_len == 0 && !(require_type_space && space == subst::TypeSpace) {
|
||||
substs.types.replace(space, fcx.infcx().next_ty_vars(desired.len()));
|
||||
substs.types.replace(space, fcx.infcx().type_vars_for_defs(&desired[..]));
|
||||
return;
|
||||
}
|
||||
|
||||
|
23
src/test/compile-fail/default_ty_param_conflict.rs
Normal file
23
src/test/compile-fail/default_ty_param_conflict.rs
Normal file
@ -0,0 +1,23 @@
|
||||
// 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.
|
||||
|
||||
use std::fmt::Debug;
|
||||
|
||||
// Example from the RFC
|
||||
fn foo<F:Default=usize>() -> F { F::default() }
|
||||
fn bar<B:Debug=isize>(b: B) { println!("{:?}", b); }
|
||||
|
||||
fn main() {
|
||||
// Here, F is instantiated with $0=uint
|
||||
let x = foo();
|
||||
|
||||
// Here, B is instantiated with $1=uint, and constraint $0 <: $1 is added.
|
||||
bar(x);
|
||||
}
|
17
src/test/compile-fail/default_ty_param_type_alias.rs
Normal file
17
src/test/compile-fail/default_ty_param_type_alias.rs
Normal file
@ -0,0 +1,17 @@
|
||||
// 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.
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
type IntMap<K=usize> = HashMap<K, usize>;
|
||||
|
||||
fn main() {
|
||||
let x = IntMap::new();
|
||||
}
|
22
src/test/run-pass/default_ty_param_method_call_test.rs
Normal file
22
src/test/run-pass/default_ty_param_method_call_test.rs
Normal file
@ -0,0 +1,22 @@
|
||||
// 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.
|
||||
|
||||
struct Foo;
|
||||
|
||||
impl Foo {
|
||||
fn method<A:Default=String>(&self) -> A {
|
||||
A::default()
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let f = Foo.method();
|
||||
println!("{}", f);
|
||||
}
|
21
src/test/run-pass/default_ty_param_struct.rs
Normal file
21
src/test/run-pass/default_ty_param_struct.rs
Normal file
@ -0,0 +1,21 @@
|
||||
// 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.
|
||||
|
||||
struct Foo<A>(A);
|
||||
|
||||
impl<A:Default=i32> Foo<A> {
|
||||
fn new() -> Foo<A> {
|
||||
Foo(A::default())
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let foo = Foo::new();
|
||||
}
|
23
src/test/run-pass/default_ty_param_trait_impl.rs
Normal file
23
src/test/run-pass/default_ty_param_trait_impl.rs
Normal file
@ -0,0 +1,23 @@
|
||||
// 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.
|
||||
|
||||
// Another example from the RFC
|
||||
trait Foo { }
|
||||
trait Bar { }
|
||||
|
||||
impl<T:Bar=usize> Foo for Vec<T> {} // Impl 1
|
||||
impl Bar for usize { } // Impl 2
|
||||
|
||||
fn takes_foo<F:Foo>(f: F) { }
|
||||
|
||||
fn main() {
|
||||
let x = Vec::new(); // x: Vec<$0>
|
||||
takes_foo(x); // adds oblig Vec<$0> : Foo
|
||||
}
|
26
src/test/run-pass/default_ty_param_trait_impl_simple.rs
Normal file
26
src/test/run-pass/default_ty_param_trait_impl_simple.rs
Normal file
@ -0,0 +1,26 @@
|
||||
// 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.
|
||||
|
||||
// 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 1
|
||||
|
||||
impl Bar for usize { } // Impl 2
|
||||
|
||||
// fn takes_foo<F:Foo>(f: F) { }
|
||||
|
||||
fn main() {
|
||||
let x = Vec::new(); // x: Vec<$0>
|
||||
x.takes_foo(); // adds oblig Vec<$0> : Foo
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user