From 3730dfdaf58057466a2c576184c4647840daaeac Mon Sep 17 00:00:00 2001 From: Matthias Devlamynck Date: Tue, 26 Sep 2017 11:43:33 +0200 Subject: [PATCH 1/2] impl Trait in argument position desugaring: Add a flag to hir and ty TypeParameterDef and raise an error when using explicit type parameters when calling a function using impl Trait in argument position. --- src/librustc/hir/lowering.rs | 4 +++ src/librustc/hir/mod.rs | 8 +++++ src/librustc/ich/impls_hir.rs | 7 ++++- src/librustc/ich/impls_ty.rs | 3 +- src/librustc/ty/mod.rs | 2 ++ src/librustc_typeck/check/mod.rs | 31 +++++++++++++++++++ src/librustc_typeck/collect.rs | 3 ++ src/librustc_typeck/diagnostics.rs | 2 ++ src/libsyntax/feature_gate.rs | 6 ++++ src/test/compile-fail/synthetic-param.rs | 38 ++++++++++++++++++++++++ 10 files changed, 102 insertions(+), 2 deletions(-) create mode 100644 src/test/compile-fail/synthetic-param.rs diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 95b8e49d60c..769f1cbcb5d 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -1103,6 +1103,10 @@ impl<'a> LoweringContext<'a> { default: tp.default.as_ref().map(|x| self.lower_ty(x)), span: tp.span, pure_wrt_drop: tp.attrs.iter().any(|attr| attr.check_name("may_dangle")), + synthetic: tp.attrs.iter() + .filter(|attr| attr.check_name("rustc_synthetic")) + .map(|_| hir::SyntheticTyParamKind::ImplTrait) + .nth(0), } } diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index bff71155440..9bfedd7a381 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -351,6 +351,7 @@ pub struct TyParam { pub default: Option>, pub span: Span, pub pure_wrt_drop: bool, + pub synthetic: Option, } /// Represents lifetimes and type parameters attached to a declaration @@ -419,6 +420,13 @@ impl Generics { } } +/// Synthetic Type Parameters are converted to an other form during lowering, this allows +/// to track the original form they had. Usefull for error messages. +#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +pub enum SyntheticTyParamKind { + ImplTrait +} + /// A `where` clause in a definition #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub struct WhereClause { diff --git a/src/librustc/ich/impls_hir.rs b/src/librustc/ich/impls_hir.rs index 96d5940caf6..776f85cf5da 100644 --- a/src/librustc/ich/impls_hir.rs +++ b/src/librustc/ich/impls_hir.rs @@ -177,7 +177,8 @@ impl_stable_hash_for!(struct hir::TyParam { bounds, default, span, - pure_wrt_drop + pure_wrt_drop, + synthetic }); impl_stable_hash_for!(struct hir::Generics { @@ -187,6 +188,10 @@ impl_stable_hash_for!(struct hir::Generics { span }); +impl_stable_hash_for!(enum hir::SyntheticTyParamKind { + ImplTrait +}); + impl_stable_hash_for!(struct hir::WhereClause { id, predicates diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index 2bbf807807b..fe060aaf426 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -463,7 +463,8 @@ impl_stable_hash_for!(struct ty::TypeParameterDef { index, has_default, object_lifetime_default, - pure_wrt_drop + pure_wrt_drop, + synthetic }); impl<'gcx, T> HashStable> diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 2c1b3e28ffb..da635ec80fc 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -675,6 +675,8 @@ pub struct TypeParameterDef { /// on generic parameter `T`, asserts data behind the parameter /// `T` won't be accessed during the parent type's `Drop` impl. pub pure_wrt_drop: bool, + + pub synthetic: Option, } #[derive(Copy, Clone, RustcEncodable, RustcDecodable)] diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 6fe49644fe8..a06f7b7f63b 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -4647,6 +4647,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // a problem. self.check_path_parameter_count(span, &mut type_segment, false); self.check_path_parameter_count(span, &mut fn_segment, false); + self.check_impl_trait(span, &mut fn_segment); let (fn_start, has_self) = match (type_segment, fn_segment) { (_, Some((_, generics))) => { @@ -4871,6 +4872,36 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } + /// Report error if there is an explicit type parameter when using `impl Trait`. + fn check_impl_trait(&self, + span: Span, + segment: &mut Option<(&hir::PathSegment, &ty::Generics)>) { + use hir::SyntheticTyParamKind::*; + + segment.map(|(path_segment, generics)| { + let explicit = !path_segment.infer_types; + let impl_trait = generics.types.iter() + .any(|ty_param| { + match ty_param.synthetic { + Some(ImplTrait) => true, + _ => false, + } + }); + + if explicit && impl_trait { + let mut err = struct_span_err! { + self.tcx.sess, + span, + E0631, + "cannot provide explicit type parameters when `impl Trait` is \ + used in argument position." + }; + + err.emit(); + } + }); + } + fn structurally_resolve_type_or_else(&self, sp: Span, ty: Ty<'tcx>, f: F) -> Ty<'tcx> where F: Fn() -> Ty<'tcx> diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index a36594cb6e5..229a1084b0c 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -922,6 +922,7 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, has_default: false, object_lifetime_default: rl::Set1::Empty, pure_wrt_drop: false, + synthetic: None, }); allow_defaults = true; @@ -993,6 +994,7 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, object_lifetime_default: object_lifetime_defaults.as_ref().map_or(rl::Set1::Empty, |o| o[i]), pure_wrt_drop: p.pure_wrt_drop, + synthetic: p.synthetic, } }); let mut types: Vec<_> = opt_self.into_iter().chain(types).collect(); @@ -1009,6 +1011,7 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, has_default: false, object_lifetime_default: rl::Set1::Empty, pure_wrt_drop: false, + synthetic: None, })); }); } diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 6bbe2233ff1..4ad1697136a 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -4677,4 +4677,6 @@ register_diagnostics! { E0592, // duplicate definitions with name `{}` // E0613, // Removed (merged with E0609) E0627, // yield statement outside of generator literal + E0631, // cannot provide explicit type parameters when `impl Trait` is used in + // argument position. } diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 5c730aaa8d0..246300a24a9 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -724,6 +724,12 @@ pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeG is just used for rustc unit tests \ and will never be stable", cfg_fn!(rustc_attrs))), + ("rustc_synthetic", Whitelisted, Gated(Stability::Unstable, + "rustc_attrs", + "this attribute \ + is just used for rustc unit tests \ + and will never be stable", + cfg_fn!(rustc_attrs))), ("rustc_symbol_name", Whitelisted, Gated(Stability::Unstable, "rustc_attrs", "internal rustc attributes will never be stable", diff --git a/src/test/compile-fail/synthetic-param.rs b/src/test/compile-fail/synthetic-param.rs new file mode 100644 index 00000000000..a9762e383fe --- /dev/null +++ b/src/test/compile-fail/synthetic-param.rs @@ -0,0 +1,38 @@ +// 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. + +#![feature(generic_param_attrs, rustc_attrs)] + +fn func<#[rustc_synthetic] T>(_: T) {} + +struct Foo; + +impl Foo { + pub fn func<#[rustc_synthetic] T>(_: T) {} +} + +struct Bar { + t: S +} + +impl Bar { + pub fn func<#[rustc_synthetic] T>(_: T) {} +} + +fn main() { + func::(42); //~ ERROR cannot provide explicit type parameters + func(42); // Ok + + Foo::func::(42); //~ ERROR cannot provide explicit type parameters + Foo::func(42); // Ok + + Bar::::func::(42); //~ ERROR cannot provide explicit type parameters + Bar::::func(42); // Ok +} From 838105f09b407aa6e5239ac1aa68e53846b5b712 Mon Sep 17 00:00:00 2001 From: Matthias Devlamynck Date: Tue, 26 Sep 2017 20:51:22 +0200 Subject: [PATCH 2/2] Use a different error code to avoid conflicts --- src/librustc_typeck/check/mod.rs | 2 +- src/librustc_typeck/diagnostics.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index a06f7b7f63b..a0099a48c89 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -4892,7 +4892,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let mut err = struct_span_err! { self.tcx.sess, span, - E0631, + E0632, "cannot provide explicit type parameters when `impl Trait` is \ used in argument position." }; diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 4ad1697136a..8df97355574 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -4677,6 +4677,6 @@ register_diagnostics! { E0592, // duplicate definitions with name `{}` // E0613, // Removed (merged with E0609) E0627, // yield statement outside of generator literal - E0631, // cannot provide explicit type parameters when `impl Trait` is used in + E0632, // cannot provide explicit type parameters when `impl Trait` is used in // argument position. }