Repository navigation
error 282: If we have no info about the actual type param, say something about the formal type param #36554
Description
Activity
- addedA-type-systemArea: Type systemArea: Type systemA-diagnosticsArea: Messages for errors, warnings, and lintsArea: Messages for errors, warnings, and lints
on Sep 17, 2016 Yeah, this stinks. Should be fairly easy to fix though. I am happy to mentor someone. I think the basic way to fix it as follows.
Step 1. Adjust the type inference variables to (optionally) carry information about what type parameter they correspond to (not all type inference variables come from a parameter) and the span where they are created.
- The code that creates a type inference variable in that situation is here.
- You can see here that they already sort of have this information: they carry a default, which can trace them back to a def-id, but only if the type parameter has a default value.
- I think we want to adjust this struct,
TypeVariableData, and add anoriginfield of typeOption<TypeVariableOrigin>(which we are about to define). - We would add a new struct
TypeVariableOriginthat contains aname: ast::Namefield and aspan: Span.- Future bonus points: Just storing the name isn't really enough to let us print out where the
TypeParameterDefwas declared. But the data structures are setup in various annoying ways to make that just a bit painful, so as a start, let's just do the name. We can improve in a later refactoring to give more context.
- Future bonus points: Just storing the name isn't really enough to let us print out where the
- We should also add a helper
var_origin()toTypeVariablesthat gives you the origin information for a givenTyVid; something like this routine, except that it would return theoriginfield and not diverging. - We would then adjust the
new_varroutine to also take an optional origin. Existing callers can mostly just useNone, except for this one that we were looking at before, which can supplySomewith the given info.- We can get the
namefrom theTypeParameterDef. - The span is given as a parameter.
- Bonus points: modify the other callers to at least thread a span through, and instead of having a
origin: Option<TypeVariableOrigin>, change it toorigin: TypeVariableOriginand make the def-id optional (i.e., so that we can always rely on having at least a span for every type-variable). - Extra bonus points: Create a richer enum for type variable origins, similar to RegionVariableOrigin, and thread that through to every caller. Now we would actually have a better way to describe why every variable exists, which we can use later.
- We can get the
OK, now that we have the info we need, we need to incorporate it into the print-out. I have to run and do something else, so i'll leave a follow-up comment with step 2.
- addedE-mentorCall for participation: This issue has a mentor. Use #t-compiler/help on Zulip for discussion.Call for participation: This issue has a mentor. Use #t-compiler/help on Zulip for discussion.
on Nov 4, 2016 Step 2. Augment the "unable to infer enough type information about
{}" message.- This message is emitted here; the
selfin this case is anInferCtxt, which is perfect. - You would want to check whether the variable
tycorresponds to just a type variable. - Probably a good idea to be defensive and start with
let ty = self.resolve_type_vars_if_possible(&ty);(I am intentionally just shadowing the oldty); this will get the most up-to-date inference information. - Something like
match ty.sty { ty::TyInfer(ty::InferTy(ty_vid)) => ... /* new code */, _ => /* existing code */ } - In the new code case, we now have a
ty_vid(of typeTyVid):- We can use the
var_origin()helper we added to learn about it's origin- something like
self.type_variables.borrow().var_origin(ty_vid)
- something like
- We can then print a message like:
- We can use the
self.sess.span_err(var_origin.span, "cannot infer value for type parameter `{}`", var_origin.name) .emit()Note that we only have the name of the variable available, not the name of the method or fn where the variable was declared. As I said, we can refactor to support that later -- it's a relatively small delta on this other plumbing.
- This message is emitted here; the
I am new to Rust but wanting to learn more and help make it better. I'd like to give a second shot at helping out.
@Coder206 sorry, but I didn't mention that I've already been working on this.
@KiChjang That's fine. Sorry for intruding on your issue. So you are doing this too: #36554 (comment) ?
@nikomatsakis I'm planning to go the enum route and give
TypeVariableOrigindifferent reasons for making a type variable. What exactly are the reasons to create one? Do I go through the call stack ofnew_varin order to find out why? I currently have something like the following:pub enum TypeVariableOrigin { TypeParameterDefinition(Span, ast::Name), TransformedUpvar(Span, ast::Name), AdjustNeverToAny(Span, ast::Name), DivergingStatement(Span, ast::Name), DivergingBlockExpression(Span, ast::Name), }
@KiChjang yes, in general
new_vardoesn't know why the variable is created, the caller has to tell it (by supplying aTypeVariableOrigin)Pinging @KiChjang - get any further with this?
@jonathandturner I'm still trying to supply a TypeVariableOrigin to all callers of
new_varthe last time I worked on it.- added a commit that references this issue
on Dec 12, 2016
e.g.,
and inline:
This is when calling a function with a generic type parameter. The actual type parameter is inferred, so we can't name it, but there is a corresponding formal parameter we could name.
E.g., if calling
foo<T>(...)we havefoo(...)and so get a type error for_, but we could mentionThere, something like