When converting parameters for an object type, be careful of defaults that reference Self
.
Fixes #18956.
This commit is contained in:
parent
f1bb6c2f46
commit
02e1d5ec06
4 changed files with 81 additions and 6 deletions
|
@ -508,13 +508,26 @@ pub fn parameterized<'tcx,GG>(cx: &ctxt<'tcx>,
|
|||
// avoid those ICEs.
|
||||
let generics = get_generics();
|
||||
|
||||
let has_self = substs.self_ty().is_some();
|
||||
let tps = substs.types.get_slice(subst::TypeSpace);
|
||||
let ty_params = generics.types.get_slice(subst::TypeSpace);
|
||||
let has_defaults = ty_params.last().map_or(false, |def| def.default.is_some());
|
||||
let num_defaults = if has_defaults {
|
||||
ty_params.iter().zip(tps.iter()).rev().take_while(|&(def, &actual)| {
|
||||
match def.default {
|
||||
Some(default) => default.subst(cx, substs) == actual,
|
||||
Some(default) => {
|
||||
if !has_self && ty::type_has_self(default) {
|
||||
// In an object type, there is no `Self`, and
|
||||
// thus if the default value references Self,
|
||||
// the user will be required to give an
|
||||
// explicit value. We can't even do the
|
||||
// substitution below to check without causing
|
||||
// an ICE. (#18956).
|
||||
false
|
||||
} else {
|
||||
default.subst(cx, substs) == actual
|
||||
}
|
||||
}
|
||||
None => false
|
||||
}
|
||||
}).count()
|
||||
|
|
|
@ -404,17 +404,30 @@ fn create_substs_for_ast_path<'tcx>(
|
|||
|
||||
let actual_supplied_ty_param_count = substs.types.len(TypeSpace);
|
||||
for param in &ty_param_defs[actual_supplied_ty_param_count..] {
|
||||
match param.default {
|
||||
Some(default) => {
|
||||
if let Some(default) = param.default {
|
||||
// If we are converting an object type, then the
|
||||
// `Self` parameter is unknown. However, some of the
|
||||
// other type parameters may reference `Self` in their
|
||||
// defaults. This will lead to an ICE if we are not
|
||||
// careful!
|
||||
if self_ty.is_none() && ty::type_has_self(default) {
|
||||
tcx.sess.span_err(
|
||||
span,
|
||||
&format!("the type parameter `{}` must be explicitly specified \
|
||||
in an object type because its default value `{}` references \
|
||||
the type `Self`",
|
||||
param.name.user_string(tcx),
|
||||
default.user_string(tcx)));
|
||||
substs.types.push(TypeSpace, tcx.types.err);
|
||||
} else {
|
||||
// This is a default type parameter.
|
||||
let default = default.subst_spanned(tcx,
|
||||
&substs,
|
||||
Some(span));
|
||||
substs.types.push(TypeSpace, default);
|
||||
}
|
||||
None => {
|
||||
tcx.sess.span_bug(span, "extra parameter without default");
|
||||
}
|
||||
} else {
|
||||
tcx.sess.span_bug(span, "extra parameter without default");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
||||
// Test a default that references `Self` which is then used in an
|
||||
// object type. Issue #18956. In this case, the value is supplied by
|
||||
// the user, but pretty-printing the type during the error message
|
||||
// caused an ICE.
|
||||
|
||||
trait MyAdd<Rhs=Self> { fn add(&self, other: &Rhs) -> Self; }
|
||||
|
||||
impl MyAdd for i32 {
|
||||
fn add(&self, other: &i32) -> i32 { *self + *other }
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x = 5;
|
||||
let y = x as MyAdd<i32>;
|
||||
//~^ ERROR as `MyAdd<i32>`
|
||||
}
|
|
@ -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.
|
||||
|
||||
// Test a default that references `Self` which is then used in an object type.
|
||||
// Issue #18956.
|
||||
|
||||
#![feature(default_type_params)]
|
||||
|
||||
trait Foo<T=Self> {
|
||||
fn method(&self);
|
||||
}
|
||||
|
||||
fn foo(x: &Foo) { }
|
||||
//~^ ERROR the type parameter `T` must be explicitly specified
|
||||
|
||||
fn main() { }
|
Loading…
Add table
Add a link
Reference in a new issue