Skip to content
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

error 282: If we have no info about the actual type param, say something about the formal type param #36554

Closed
nrc opened this issue Sep 17, 2016 · 9 comments
Labels
A-diagnostics Area: Messages for errors, warnings, and lints A-type-system Area: Type system E-mentor Call for participation: This issue has a mentor. Use #t-compiler/help on Zulip for discussion.

Comments

@nrc
Copy link
Member

nrc commented Sep 17, 2016

e.g.,

unable to infer enough type information about `_`

and inline:

cannot infer type for `_`

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 have foo(...) and so get a type error for _, but we could mention T here, something like

cannot infer type for `_`, the inferred type corresponding to `T` in this call to `foo`
@nrc nrc added A-type-system Area: Type system A-diagnostics Area: Messages for errors, warnings, and lints labels Sep 17, 2016
@nikomatsakis
Copy link
Contributor

nikomatsakis commented Nov 4, 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 an origin field of type Option<TypeVariableOrigin> (which we are about to define).
  • We would add a new struct TypeVariableOrigin that contains a name: ast::Name field and a span: Span.
    • Future bonus points: Just storing the name isn't really enough to let us print out where the TypeParameterDef was 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.
  • We should also add a helper var_origin() to TypeVariables that gives you the origin information for a given TyVid; something like this routine, except that it would return the origin field and not diverging.
  • We would then adjust the new_var routine to also take an optional origin. Existing callers can mostly just use None, except for this one that we were looking at before, which can supply Some with the given info.
    • We can get the name from the TypeParameterDef.
    • 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 to origin: TypeVariableOrigin and 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.

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.

@nikomatsakis nikomatsakis added the E-mentor Call for participation: This issue has a mentor. Use #t-compiler/help on Zulip for discussion. label Nov 4, 2016
@nikomatsakis
Copy link
Contributor

Step 2. Augment the "unable to infer enough type information about {}" message.

  • This message is emitted here; the self in this case is an InferCtxt, which is perfect.
  • You would want to check whether the variable ty corresponds 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 old ty); 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 type TyVid):
    • 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)
    • We can then print a message like:
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.

@Coder206
Copy link

Coder206 commented Nov 4, 2016

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.

@KiChjang
Copy link
Member

KiChjang commented Nov 4, 2016

@Coder206 sorry, but I didn't mention that I've already been working on this.

@Coder206
Copy link

Coder206 commented Nov 4, 2016

@KiChjang That's fine. Sorry for intruding on your issue. So you are doing this too: #36554 (comment) ?

@KiChjang
Copy link
Member

KiChjang commented Nov 6, 2016

@nikomatsakis I'm planning to go the enum route and give TypeVariableOrigin different reasons for making a type variable. What exactly are the reasons to create one? Do I go through the call stack of new_var in 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),
}

@nikomatsakis
Copy link
Contributor

@KiChjang yes, in general new_var doesn't know why the variable is created, the caller has to tell it (by supplying a TypeVariableOrigin)

@sophiajt
Copy link
Contributor

Pinging @KiChjang - get any further with this?

@KiChjang
Copy link
Member

@jonathandturner I'm still trying to supply a TypeVariableOrigin to all callers of new_var the last time I worked on it.

bors added a commit that referenced this issue Dec 12, 2016
…akis

Display better error messages for E0282

Fixes #36554.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-diagnostics Area: Messages for errors, warnings, and lints A-type-system Area: Type system E-mentor Call for participation: This issue has a mentor. Use #t-compiler/help on Zulip for discussion.
Projects
None yet
Development

No branches or pull requests

5 participants