Skip to content

The Great Generics Generalisation: HIR Followup #51880

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 41 commits into from
Aug 20, 2018
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
11adc13
Address minor comments
varkor Jun 22, 2018
651215e
Replace for_each with for
varkor Jun 22, 2018
2317abd
Fix quadratic loop in confirm.rs
varkor Jun 22, 2018
d1a82af
Refactor mod/check (part i)
varkor Jun 25, 2018
5fe9aeb
Refactor mod/check (part ii)
varkor Jun 26, 2018
96379e1
Refactor mod/check (part iii)
varkor Jun 26, 2018
e812b55
Refactor mod/check (part iv)
varkor Jun 26, 2018
c9941a8
Refactor mod/check (part v)
varkor Jun 26, 2018
88d5b2f
Refactor mod/check (part vi)
varkor Jun 28, 2018
3357702
Replace generics_require_inlining with generics.requires_monomorphiza…
varkor Jun 28, 2018
734ce4a
Fix tidy check
varkor Jun 28, 2018
d5e24dc
Fix integer overflow
varkor Jul 2, 2018
d8ba103
Fix param_idx calculation
varkor Jul 3, 2018
b6eef18
Supress consecutive errors
varkor Jul 3, 2018
84edc0a
Move lifetime calculation outside loop
varkor Jul 3, 2018
35ddd46
Refactor confirm.rs
varkor Jul 3, 2018
340a7fc
Refactor astconv.rs
varkor Jul 3, 2018
e02642d
Fix confirm.rs
varkor Jul 3, 2018
9cfe92c
"Fix" annoying test
varkor Jul 3, 2018
9bb40b0
Make prohibit_generics take IntoIterators
varkor Jul 23, 2018
db94efa
Refactor mod/check (part vii)
varkor Jul 23, 2018
5f2588f
Fix behaviour in error condition
varkor Jul 23, 2018
08d49a6
Refactor mod/check (part viii)
varkor Jul 24, 2018
5d07db4
Refactor confirm.rs (part ii)
varkor Jul 24, 2018
b524991
Refactor astconv.rs (part ii)
varkor Jul 24, 2018
ccef306
Revert broken test
varkor Jul 24, 2018
e79bc41
Consolidate into create_substs_for_generic_args
varkor Jul 24, 2018
6a96cf1
Clean match statement
varkor Aug 2, 2018
9d3d4b1
Refactor lock-step
varkor Aug 7, 2018
7c9f7c2
Args first, then params
varkor Aug 7, 2018
a14bc71
Add Default for GenericParamCount
varkor Aug 7, 2018
49c4573
Refactor generic argument count check in astconv
varkor Aug 7, 2018
68b0e7d
Refactor generic argument count check in method/confirm.rs
varkor Aug 7, 2018
04d33bb
Refactor generic argument count check in check/mod.rs
varkor Aug 7, 2018
03c4628
Avoid clone and update documentation
varkor Aug 8, 2018
4722744
Fix some remaining tests
varkor Aug 8, 2018
25b6267
Taking a peek
varkor Aug 19, 2018
b5c2470
Update new ui tests
varkor Aug 19, 2018
ae81fc6
Fix ICE
varkor Aug 19, 2018
aa3b5c5
Fix diagnostic regression
varkor Aug 20, 2018
ee9bd0f
Add a test for skipping all arguments versus just one
varkor Aug 20, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Fix diagnostic regression
  • Loading branch information
varkor committed Aug 20, 2018
commit aa3b5c58e44beca0e96b46deb24f1bcb8d8c98a1
4 changes: 3 additions & 1 deletion src/librustc_passes/ast_validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -539,7 +539,9 @@ impl<'a> Visitor<'a> for NestedImplTraitVisitor<'a> {
fn visit_generic_args(&mut self, _: Span, generic_args: &'a GenericArgs) {
match *generic_args {
GenericArgs::AngleBracketed(ref data) => {
data.args.iter().for_each(|arg| self.visit_generic_arg(arg));
for arg in &data.args {
self.visit_generic_arg(arg)
}
for type_binding in &data.bindings {
// Type bindings such as `Item=impl Debug` in `Iterator<Item=Debug>`
// are allowed to contain nested `impl Trait`.
Expand Down
73 changes: 36 additions & 37 deletions src/librustc_typeck/astconv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,11 +94,12 @@ struct ConvertedBinding<'tcx> {

#[derive(PartialEq)]
enum GenericArgPosition {
Datatype,
Function,
Method,
Type,
Value, // e.g. functions
MethodCall,
}

// FIXME(#53525): these error codes should all be unified.
struct GenericArgMismatchErrorCode {
lifetimes: (&'static str, &'static str),
types: (&'static str, &'static str),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you open an issue and write a FIXME here, about uniformizing these? Error codes are sad business and in this case, there shouldn't be more than one error.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Opened #53525.

Expand Down Expand Up @@ -255,9 +256,9 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
&empty_args
},
if is_method_call {
GenericArgPosition::Method
GenericArgPosition::MethodCall
} else {
GenericArgPosition::Function
GenericArgPosition::Value
},
def.parent.is_none() && def.has_self, // `has_self`
seg.infer_types || suppress_mismatch, // `infer_types`
Expand Down Expand Up @@ -285,7 +286,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
// arguments in order to validate them with respect to the generic parameters.
let param_counts = def.own_counts();
let arg_counts = args.own_counts();
let infer_lifetimes = position != GenericArgPosition::Datatype && arg_counts.lifetimes == 0;
let infer_lifetimes = position != GenericArgPosition::Type && arg_counts.lifetimes == 0;

let mut defaults: ty::GenericParamCount = Default::default();
for param in &def.params {
Expand All @@ -297,7 +298,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
};
}

if position != GenericArgPosition::Datatype && !args.bindings.is_empty() {
if position != GenericArgPosition::Type && !args.bindings.is_empty() {
AstConv::prohibit_assoc_ty_binding(tcx, args.bindings[0].span);
}

Expand All @@ -308,7 +309,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
if late bound lifetime parameters are present";
let note = "the late bound lifetime parameter is introduced here";
let span = args.args[0].span();
if position == GenericArgPosition::Function
if position == GenericArgPosition::Value
&& arg_counts.lifetimes != param_counts.lifetimes {
let mut err = tcx.sess.struct_span_err(span, msg);
err.span_note(span_late, note);
Expand All @@ -328,7 +329,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
kind,
required,
permitted,
provided| {
provided,
offset| {
// We enforce the following: `required` <= `provided` <= `permitted`.
// For kinds without defaults (i.e. lifetimes), `required == permitted`.
// For other kinds (i.e. types), `permitted` may be greater than `required`.
Expand All @@ -348,8 +350,15 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
(required, "")
};

let mut span = span;
let label = if required == permitted && provided > permitted {
let diff = provided - permitted;
if diff == 1 {
// In the case when the user has provided too many arguments,
// we want to point to the first unexpected argument.
let first_superfluous_arg: &GenericArg = &args.args[offset + permitted];
span = first_superfluous_arg.span();
}
format!(
"{}unexpected {} argument{}",
if diff != 1 { format!("{} ", diff) } else { String::new() },
Expand Down Expand Up @@ -394,6 +403,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
param_counts.lifetimes,
param_counts.lifetimes,
arg_counts.lifetimes,
0,
);
}
if !infer_types
Expand All @@ -404,6 +414,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
param_counts.types - defaults.types - has_self as usize,
param_counts.types - has_self as usize,
arg_counts.types,
arg_counts.lifetimes,
)
} else {
false
Expand Down Expand Up @@ -491,59 +502,50 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
// provided, matching them with the generic parameters we expect.
// Mismatches can occur as a result of elided lifetimes, or for malformed
// input. We try to handle both sensibly.
let mut progress_arg = true;
match (args.peek(), params.peek()) {
(Some(&arg), Some(&param)) => {
match (arg, &param.kind) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, what you do think about flipping the order between these, so it's more like (expected, found)? IMO that's easier to read, but I'm not sure it is for other people.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I originally had that, then decided that (found, expected) was easier to read :P

(GenericArg::Lifetime(_), GenericParamDefKind::Lifetime) => {
(GenericArg::Lifetime(_), GenericParamDefKind::Lifetime)
| (GenericArg::Type(_), GenericParamDefKind::Type { .. }) => {
push_kind(&mut substs, provided_kind(param, arg));
args.next();
params.next();
}
(GenericArg::Lifetime(_), GenericParamDefKind::Type { .. }) => {
// We expected a type argument, but got a lifetime
// argument. This is an error, but we need to handle it
// gracefully so we can report sensible errors. In this
// case, we're simply going to infer the remaining
// arguments.
args.by_ref().for_each(drop); // Exhaust the iterator.
}
(GenericArg::Type(_), GenericParamDefKind::Type { .. }) => {
push_kind(&mut substs, provided_kind(param, arg));
params.next();
// case, we're simply going to infer this argument.
args.next();
}

This comment was marked as resolved.

(GenericArg::Type(_), GenericParamDefKind::Lifetime) => {
// We expected a lifetime argument, but got a type
// argument. That means we're inferring the lifetimes.
push_kind(&mut substs, inferred_kind(None, param, infer_types));
params.next();
progress_arg = false;
}
}
}
(Some(_), None) => {
// We should never be able to reach this point with well-formed input.
// Getting to this point means the user supplied more arguments than
// there are parameters.
args.next();
}
(None, Some(&param)) => {
// If there are fewer arguments than parameters, it means
// we're inferring the remaining arguments.
match param.kind {
GenericParamDefKind::Lifetime => {
push_kind(&mut substs, inferred_kind(None, param, infer_types));
}
GenericParamDefKind::Type { .. } => {
GenericParamDefKind::Lifetime | GenericParamDefKind::Type { .. } => {
let kind = inferred_kind(Some(&substs), param, infer_types);
push_kind(&mut substs, kind);

This comment was marked as resolved.

This comment was marked as resolved.

}
}
args.next();
params.next();
}
(None, None) => break,
}
if progress_arg {
args.next();
}
}
}

Expand Down Expand Up @@ -582,12 +584,12 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
span,
&generic_params,
&generic_args,
GenericArgPosition::Datatype,
GenericArgPosition::Type,
has_self,
infer_types,
GenericArgMismatchErrorCode {
lifetimes: ("E0107", "E0107"),
types: ("E0243", "E0244"), // FIXME: E0243 and E0244 should be unified.
types: ("E0243", "E0244"),
},
);

Expand Down Expand Up @@ -616,17 +618,14 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
|_| (Some(generic_args), infer_types),
// Provide substitutions for parameters for which (valid) arguments have been provided.
|param, arg| {
match param.kind {
GenericParamDefKind::Lifetime => match arg {
GenericArg::Lifetime(lt) => {
self.ast_region_to_region(&lt, Some(param)).into()
}
_ => unreachable!(),
match (&param.kind, arg) {
(GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => {
self.ast_region_to_region(&lt, Some(param)).into()
}
GenericParamDefKind::Type { .. } => match arg {
GenericArg::Type(ty) => self.ast_ty_to_ty(&ty).into(),
_ => unreachable!(),
(GenericParamDefKind::Type { .. }, GenericArg::Type(ty)) => {
self.ast_ty_to_ty(&ty).into()
}
_ => unreachable!(),
}
},
// Provide substitutions for parameters for which arguments are inferred.
Expand Down
15 changes: 6 additions & 9 deletions src/librustc_typeck/check/method/confirm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -344,17 +344,14 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
},
// Provide substitutions for parameters for which (valid) arguments have been provided.
|param, arg| {
match param.kind {
GenericParamDefKind::Lifetime => match arg {
GenericArg::Lifetime(lt) => {
AstConv::ast_region_to_region(self.fcx, lt, Some(param)).into()
}
_ => unreachable!(),
match (&param.kind, arg) {
(GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => {
AstConv::ast_region_to_region(self.fcx, lt, Some(param)).into()
}
GenericParamDefKind::Type { .. } => match arg {
GenericArg::Type(ty) => self.to_ty(ty).into(),
_ => unreachable!(),
(GenericParamDefKind::Type { .. }, GenericArg::Type(ty)) => {
self.to_ty(ty).into()
}
_ => unreachable!(),
}
},
// Provide substitutions for parameters for which arguments are inferred.
Expand Down
38 changes: 18 additions & 20 deletions src/librustc_typeck/check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,11 +109,11 @@ use session::{CompileIncomplete, config, Session};
use TypeAndSubsts;
use lint;
use util::common::{ErrorReported, indenter};
use util::nodemap::{DefIdMap, DefIdSet, FxHashMap, NodeMap};
use util::nodemap::{DefIdMap, DefIdSet, FxHashMap, FxHashSet, NodeMap};

use std::cell::{Cell, RefCell, Ref, RefMut};
use rustc_data_structures::sync::Lrc;
use std::collections::{hash_map::Entry, HashSet};
use std::collections::hash_map::Entry;
use std::cmp;
use std::fmt::Display;
use std::iter;
Expand Down Expand Up @@ -4908,7 +4908,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
// provided (if any) into their appropriate spaces. We'll also report
// errors if type parameters are provided in an inappropriate place.

let mut generic_segs = HashSet::new();
let mut generic_segs = FxHashSet::default();
for PathSeg(_, index) in &path_segs {
generic_segs.insert(index);
}
Expand Down Expand Up @@ -4937,24 +4937,25 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
// to add defaults. If the user provided *too many* types, that's
// a problem.

let mut suppress_errors = FxHashMap();
let mut infer_args_for_err = FxHashSet::default();
for &PathSeg(def_id, index) in &path_segs {
let seg = &segments[index];
let generics = self.tcx.generics_of(def_id);
// `impl Trait` is treated as a normal generic parameter internally,
// but we don't allow users to specify the parameter's value
// explicitly, so we have to do some error-checking here.
let suppress = AstConv::check_generic_arg_count_for_call(
// Argument-position `impl Trait` is treated as a normal generic
// parameter internally, but we don't allow users to specify the
// parameter's value explicitly, so we have to do some error-
// checking here.
let suppress_errors = AstConv::check_generic_arg_count_for_call(
self.tcx,
span,
&generics,
&seg,
false, // `is_method_call`
);
if suppress {
if suppress_errors {
infer_args_for_err.insert(index);
self.set_tainted_by_errors(); // See issue #53251.
}
suppress_errors.insert(index, suppress);
}

let has_self = path_segs.last().map(|PathSeg(def_id, _)| {
Expand All @@ -4976,7 +4977,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
}) {
// If we've encountered an `impl Trait`-related error, we're just

This comment was marked as resolved.

// going to infer the arguments for better error messages.
if !suppress_errors[&index] {
if !infer_args_for_err.contains(&index) {
// Check whether the user has provided generic arguments.
if let Some(ref data) = segments[index].args {
return (Some(data), segments[index].infer_types);
Expand All @@ -4989,17 +4990,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
},
// Provide substitutions for parameters for which (valid) arguments have been provided.
|param, arg| {
match param.kind {
GenericParamDefKind::Lifetime => match arg {
GenericArg::Lifetime(lt) => {
AstConv::ast_region_to_region(self, lt, Some(param)).into()
}
_ => unreachable!(),
match (&param.kind, arg) {
(GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => {
AstConv::ast_region_to_region(self, lt, Some(param)).into()
}
GenericParamDefKind::Type { .. } => match arg {
GenericArg::Type(ty) => self.to_ty(ty).into(),
_ => unreachable!(),
(GenericParamDefKind::Type { .. }, GenericArg::Type(ty)) => {
self.to_ty(ty).into()
}
_ => unreachable!(),
}
},
// Provide substitutions for parameters for which arguments are inferred.
Expand Down
16 changes: 8 additions & 8 deletions src/test/ui/bad/bad-mid-path-type-params.stderr
Original file line number Diff line number Diff line change
@@ -1,26 +1,26 @@
error[E0087]: wrong number of type arguments: expected 1, found 2
--> $DIR/bad-mid-path-type-params.rs:40:13
--> $DIR/bad-mid-path-type-params.rs:40:28
|
LL | let _ = S::new::<isize,f64>(1, 1.0);
| ^^^^^^^^^^^^^^^^^^^ unexpected type argument
| ^^^ unexpected type argument

error[E0107]: wrong number of lifetime arguments: expected 0, found 1
--> $DIR/bad-mid-path-type-params.rs:43:13
--> $DIR/bad-mid-path-type-params.rs:43:17
|
LL | let _ = S::<'a,isize>::new::<f64>(1, 1.0);
| ^^^^^^^^^^^^^^^^^^^^^^^^^ unexpected lifetime argument
| ^^ unexpected lifetime argument

error[E0087]: wrong number of type arguments: expected 1, found 2
--> $DIR/bad-mid-path-type-params.rs:46:17
--> $DIR/bad-mid-path-type-params.rs:46:36
|
LL | let _: S2 = Trait::new::<isize,f64>(1, 1.0);
| ^^^^^^^^^^^^^^^^^^^^^^^ unexpected type argument
| ^^^ unexpected type argument

error[E0088]: wrong number of lifetime arguments: expected 0, found 1
--> $DIR/bad-mid-path-type-params.rs:49:17
--> $DIR/bad-mid-path-type-params.rs:49:25
|
LL | let _: S2 = Trait::<'a,isize>::new::<f64>(1, 1.0);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unexpected lifetime argument
| ^^ unexpected lifetime argument

error: aborting due to 4 previous errors

Expand Down
8 changes: 4 additions & 4 deletions src/test/ui/constructor-lifetime-args.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ LL | S::<'static>(&0, &0);
| ^^^^^^^^^^^^ expected 2 lifetime arguments

error[E0088]: wrong number of lifetime arguments: expected 2, found 3
--> $DIR/constructor-lifetime-args.rs:29:5
--> $DIR/constructor-lifetime-args.rs:29:27
|
LL | S::<'static, 'static, 'static>(&0, &0);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unexpected lifetime argument
| ^^^^^^^ unexpected lifetime argument

error[E0090]: wrong number of lifetime arguments: expected 2, found 1
--> $DIR/constructor-lifetime-args.rs:32:5
Expand All @@ -17,10 +17,10 @@ LL | E::V::<'static>(&0);
| ^^^^^^^^^^^^^^^ expected 2 lifetime arguments

error[E0088]: wrong number of lifetime arguments: expected 2, found 3
--> $DIR/constructor-lifetime-args.rs:34:5
--> $DIR/constructor-lifetime-args.rs:34:30
|
LL | E::V::<'static, 'static, 'static>(&0);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unexpected lifetime argument
| ^^^^^^^ unexpected lifetime argument

error: aborting due to 4 previous errors

Expand Down
Loading