public Expression Compatible (ResolveContext ec, TypeSpec type)
{
Expression am;
if (compatibles.TryGetValue (type, out am))
return am;
TypeSpec delegate_type = CompatibleChecks (ec, type);
if (delegate_type == null)
return null;
//
// At this point its the first time we know the return type that is
// needed for the anonymous method. We create the method here.
//
var invoke_mb = Delegate.GetInvokeMethod (ec.Compiler, delegate_type);
TypeSpec return_type = invoke_mb.ReturnType;
//
// Second: the return type of the delegate must be compatible with
// the anonymous type. Instead of doing a pass to examine the block
// we satisfy the rule by setting the return type on the EmitContext
// to be the delegate type return type.
//
var body = CompatibleMethodBody (ec, null, return_type, delegate_type);
if (body == null)
return null;
bool etree_conversion = delegate_type != type;
try {
if (etree_conversion) {
if (ec.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
//
// Nested expression tree lambda use same scope as parent
// lambda, this also means no variable capturing between this
// and parent scope
//
am = body.Compatible (ec, ec.CurrentAnonymousMethod);
//
// Quote nested expression tree
//
if (am != null)
am = new Quote (am);
} else {
int errors = ec.Report.Errors;
using (ec.Set (ResolveContext.Options.ExpressionTreeConversion)) {
am = body.Compatible (ec);
}
//
// Rewrite expressions into expression tree when targeting Expression<T>
//
if (am != null && errors == ec.Report.Errors)
am = CreateExpressionTree (ec, delegate_type);
}
} else {
am = body.Compatible (ec);
}
} catch (CompletionResult) {
throw;
} catch (Exception e) {
throw new InternalErrorException (e, loc);
}
if (!ec.IsInProbingMode) {
compatibles.Add (type, am ?? EmptyExpression.Null);
}
return am;
}