From 02e1d5ec0613c0c6e89e4cd55376b112c57a582c Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 17 Feb 2015 10:56:26 -0500 Subject: [PATCH] When converting parameters for an object type, be careful of defaults that reference `Self`. Fixes #18956. --- src/librustc/util/ppaux.rs | 15 ++++++++++- src/librustc_typeck/astconv.rs | 23 ++++++++++++---- ...rameter-defaults-referencing-Self-ppaux.rs | 26 +++++++++++++++++++ ...ype-parameter-defaults-referencing-Self.rs | 23 ++++++++++++++++ 4 files changed, 81 insertions(+), 6 deletions(-) create mode 100644 src/test/compile-fail/type-parameter-defaults-referencing-Self-ppaux.rs create mode 100644 src/test/compile-fail/type-parameter-defaults-referencing-Self.rs diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 0363978bada2..cb928ce64bc5 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -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() diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 0183b3474a50..19cf3bb93ea1 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -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"); } } diff --git a/src/test/compile-fail/type-parameter-defaults-referencing-Self-ppaux.rs b/src/test/compile-fail/type-parameter-defaults-referencing-Self-ppaux.rs new file mode 100644 index 000000000000..8ff514e04e36 --- /dev/null +++ b/src/test/compile-fail/type-parameter-defaults-referencing-Self-ppaux.rs @@ -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 or the MIT license +// , 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 { 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; + //~^ ERROR as `MyAdd` +} diff --git a/src/test/compile-fail/type-parameter-defaults-referencing-Self.rs b/src/test/compile-fail/type-parameter-defaults-referencing-Self.rs new file mode 100644 index 000000000000..9982d4850248 --- /dev/null +++ b/src/test/compile-fail/type-parameter-defaults-referencing-Self.rs @@ -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 or the MIT license +// , 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 { + fn method(&self); +} + +fn foo(x: &Foo) { } +//~^ ERROR the type parameter `T` must be explicitly specified + +fn main() { }