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

variance error at during compilation : "Can't use implicitly 'out' variable in an 'in' position in supertype." #59833

Open
atototenten opened this issue Jan 1, 2025 · 3 comments
Labels
analyzer-spec Issues with the analyzer's implementation of the language spec area-analyzer Use area-analyzer for Dart analyzer issues, including the analysis server and code completion. P3 A lower priority bug or feature request type-bug Incorrect behavior (everything from a crash to more subtle misbehavior)

Comments

@atototenten
Copy link

hello ,

code's situation :

  • not related to flutter
  • vscode indicates no issue with the code
  • compilation fails ,in native and dart-pad

error :

main.dart:7:7: Error: Can't use implicitly 'out' variable 'value_type' in an 'in' position in supertype '_value_handling_base'.
class value_handling<value_type>
      ^

re-prod. code (simplification ,of the actual code) :

void main() {}

typedef handle_record<value_type> = ({
  void Function(value_type) value_handle,
});

class value_handling<value_type> extends _value_handling_base<handle_record<value_type>> {
  value_handling(
    this.value,
  );

  final value_type value;

  @override
  void value_handle(
    final handle_record<value_type> handles,
  ) {
    return handles.value_handle(
      value,
    );
  }
}

abstract class _value_handling_base<handles_record extends Record> {
  const _value_handling_base();

  void value_handle(
    covariant final handles_record handles,
  );
}

thanks

@lrhn
Copy link
Member

lrhn commented Jan 2, 2025

Does look to be working as intended.

You're not allowed to write

abstract class C<T>
   implements List<void Function(T)> {}

because it uses the covariant type parameter T contravariantly in the superinterface type.

That allows up-casts to be unsound.

C<int> ci = ...;
C<num> can = ci;
List<void Functions(num)> ln = cn;
List<void Functions(double)> ld = ln;

Every assignment here is an up-cast which would be allowed with no runtime type check, but they're not sound.

If VSCode shows no issue, the analyzer may not be reporting this error correctly.
This reproduces in DartPad where the program above gives no analyzer errors, but changing the type from a record type to

typedef handle_record<value_type> = void Function(value_type);

makes the covariant errors appear.

@lrhn lrhn transferred this issue from dart-lang/language Jan 2, 2025
@lrhn lrhn added area-analyzer Use area-analyzer for Dart analyzer issues, including the analysis server and code completion. type-bug Incorrect behavior (everything from a crash to more subtle misbehavior) labels Jan 2, 2025
@keertip keertip added analyzer-spec Issues with the analyzer's implementation of the language spec P3 A lower priority bug or feature request labels Jan 2, 2025
@atototenten
Copy link
Author

hi,

i know sub-typing is the core issue, of this problem .

how may i disable it ?

thanks

@lrhn
Copy link
Member

lrhn commented Jan 3, 2025

You can't disable subtyping, or the restrictions on type variables that they must occur covariantly in superclasses.

You can make sure to only use the type variable covariantly in the supertypes. If you need to parameterize with a function, wrap it in a class, not a structural type like a record.

If you check the code below, you can see that it works only using classes as wrappers for the function, so that's likely what you need to do, if you do want to use the handler type as a type argument.

void main() {
  void handle(int value) { print(value); }
  HandleType<int> handler = makeHandler(handle);
  ValueHandling<int>(42).valueHandle(handler);
}

// Uncomment one pair of lines to see effect.

// typedef HandleType<V> = HandleRecord<V>;
// HandleType<V> makeHandler<V>(void Function(V) handle) => (valueHandle: handle);

// typedef HandleType<V> = HandleFunction<V>;
// HandleType<V> makeHandler<V>(void Function(V) handle) => handle;

typedef HandleType<V> = HandleClass<V>;
HandleType<V> makeHandler<V>(void Function(V) handle) => HandleType<V>(handle);

// typedef HandleType<V> = HandleClass2<V>;
// HandleType<V> makeHandler<V>(Handle<V> handle) => HandleType<V>(handle);


typedef Handle<V> = void Function(V);

abstract class ValueHandlingBase<R> {
  const ValueHandlingBase();

  void valueHandle(covariant final R handles);
}

class ValueHandling<V>
    extends ValueHandlingBase<HandleType<V>> {
  ValueHandling(this.value);

  final V value;

  @override
  void valueHandle(final HandleType<V> handles) {
    // return handles.valueHandle(value);
    return handles.valueHandle(value);
  }
}

// Record wrapper.
typedef HandleRecord<V> = ({Handle<V> valueHandle});

// No wrapper.
typedef HandleFunction<V> = Handle<V>;
extension <V> on Handle<V> {
  void valueHandle(V value) => this(value);
}

// Class wrapper with method.
class HandleClass<V> {
  final void Function(V) _valueHandle;
  HandleClass(this._valueHandle);
  void valueHandle(V value) => _valueHandle(value);
}

// Class wrapper with direct access to function field.
class HandleClass2<V> {
  final void Function(V) valueHandle;
  HandleClass2(this.valueHandle);
}

I wanted to add an extension type wrapper too, but it won't even compile by itself because of the contravariant type variable:

extension type HandleExtensionType<V>(Handle<V> valueHandle) {}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
analyzer-spec Issues with the analyzer's implementation of the language spec area-analyzer Use area-analyzer for Dart analyzer issues, including the analysis server and code completion. P3 A lower priority bug or feature request type-bug Incorrect behavior (everything from a crash to more subtle misbehavior)
Projects
None yet
Development

No branches or pull requests

3 participants