Pular para o conteúdo principal

unsafe_variance

Saiba mais sobre a regra de lint unsafe_variance.

Experimental
Lançado no Dart 3.7

Tipo inseguro: possui uma variável de tipo em uma posição não covariante.

Detalhes

#

Uma variável de instância cujo tipo contém um parâmetro de tipo da classe, mixin ou enum que a envolve, em uma posição não covariante, provavelmente causará falhas em tempo de execução devido a verificações de tipo que falham. Por exemplo, em class C<X> {...}, uma variável de instância da forma void Function(X) myVariable; pode causar esse tipo de falha em tempo de execução.

O mesmo vale para um getter ou método cujo tipo de retorno tem uma ocorrência não covariante de um parâmetro de tipo da declaração que o envolve.

Este lint sinaliza esse tipo de declaração de membro.

RUIM:

dart
class C<X> {
  final bool Function(X) fun; // LINT
  C(this.fun);
}
​
void main() {
  C<num> c = C<int>((i) => i.isEven);
  c.fun(10); // Throws.
}

O problema é que X aparece como tipo de parâmetro no tipo de fun.

Uma forma de reduzir o risco de erros de tipo em tempo de execução é garantir que o membro não covariante fun seja somente usado em this. Não conseguimos impor isso de forma estrita, mas podemos torná-lo privado e adicionar um método de encaminhamento fun, de modo que possamos verificar localmente, na mesma biblioteca, que essa restrição é respeitada:

MELHOR:

dart
class C<X> {
  // ignore: unsafe_variance
  final bool Function(X) _fun;
  bool fun(X x) => _fun(x);
  C(this._fun);
}
​
void main() {
  C<num> c = C<int>((i) => i.isEven);
  c.fun(10); // Succeeds.
}

Uma abordagem totalmente segura exige um recurso que o Dart ainda não tem, a saber, variância verificada estaticamente. Com ele, poderíamos especificar que o parâmetro de tipo X é invariante (inout X).

É possível emular invariância sem suporte a variância verificada estaticamente. Isso impõe algumas restrições à criação de subtipos, mas fornece fielmente a tipagem que inout daria:

BOM:

dart
typedef Inv<X> = X Function(X);
typedef C<X> = _C<X, Inv<X>>;
​
class _C<X, Invariance extends Inv<X>> {
  // ignore: unsafe_variance
  final bool Function(X) fun; // Safe!
  _C(this.fun);
}
​
void main() {
  C<int> c = C<int>((i) => i.isEven);
  c.fun(10); // Succeeds.
}

Com essa abordagem, C<int> não é subtipo de C<num>, então c precisa ter um tipo declarado diferente.

Outra possibilidade é declarar a variável com um tipo seguro, porém mais geral. Assim, é seguro usar a própria variável, mas cada invocação precisará ser verificada em tempo de execução:

HONESTO:

dart
class C<X> {
  final bool Function(Never) fun;
  C(this.fun);
}
​
void main() {
  C<num> c = C<int>((int i) => i.isEven);
  var cfun = c.fun; // Local variable, enables promotion.
  if (cfun is bool Function(int)) cfun(10); // Succeeds.
  if (cfun is bool Function(bool)) cfun(true); // Not called.
}

Ativar

#

Para ativar a regra unsafe_variance, adicione unsafe_variance em linter > rules no seu arquivo analysis_options.yaml:

analysis_options.yaml
yaml
linter:
  rules:
    - unsafe_variance

Se você usa a sintaxe de mapa YAML para configurar as regras de lint, adicione unsafe_variance: true em linter > rules:

analysis_options.yaml
yaml
linter:
  rules:
    unsafe_variance: true

Encontrou essa página sem tradução ou que precisa de correção? Abra uma issue e nos ajude a manter esse site em PT-BR para ajudar pessoas como você.